Stdout in eine Datei umleiten, für die Sie keine Schreibberechtigung haben

113

Wenn Sie versuchen, eine Datei zu ändern, ohne über Schreibrechte zu verfügen, wird folgende Fehlermeldung angezeigt:

> touch /tmp/foo && sudo chown root /tmp/foo
> echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Sudoing hilft nicht weiter, da es den Befehl als root ausführt, aber die Shell das Umleiten von stdout behandelt und die Datei trotzdem öffnet:

> sudo echo test > /tmp/foo
zsh: permission denied: /tmp/foo

Gibt es eine einfache Möglichkeit, stdout zu einer Datei umzuleiten, zu der Sie keine Schreibberechtigung haben, abgesehen davon, dass Sie eine Shell als Root öffnen und die Datei auf diese Weise bearbeiten?

> sudo su
# echo test > /tmp/foo
Michael Mrozek
quelle
2
Beantworten Sie eine ähnliche Frage von StackOverflow stackoverflow.com/questions/82256/…
Cristian Ciupitu
Wie können Sie keine Berechtigung für eine Datei haben, die Sie selbst in tmp erstellt haben? ist es wegen umask?
k961,
@ k961 Früher habe ich chownden Besitzer gewechselt . Es war nur ein Beispiel
Michael Mrozek

Antworten:

116

Ja, mit tee. So echo test > /tmp/foowird es

echo test | sudo tee /tmp/foo

Sie können auch anhängen ( >>)

echo test | sudo tee -a /tmp/foo
Gert
quelle
27
Tee wird auch auf stdout ausgegeben; Manchmal möchten Sie nicht, dass der Inhalt den Bildschirm ausfüllt. Um dieses Problem zu beheben, gehen Sie wie echo test | sudo tee /tmp/foo > /dev/null
folgt vor
Wie machst du das mit heredoc?
JohnDoea
26

So ersetzen Sie den Inhalt der Datei durch die Ausgabe von echo(wie den >Shell-Umleitungsoperator).

echo test | sudo dd of=/tmp/foo

So schreiben Sie in die Datei (am Anfang, obwohl Sie sie seekfür die Ausgabe an verschiedenen Offsets verwenden können), ohne sie abzuschneiden (wie der 1<>Bourne-Shell-Operator):

echo test | sudo dd of=/tmp/foo conv=notrunc

So hängen Sie >>mit GNU an die Datei (wie ) an dd:

echo test | sudo dd of=/tmp/foo oflag=append conv=notrunc

Siehe auch GNUs dd, um conv=exclzu vermeiden, dass eine vorhandene Datei überladen wird (wie set -o noclobberin POSIX-Shells) und conv=nocreatumgekehrt (nur eine vorhandene Datei aktualisieren).

Chris Jepeway
quelle
klug! Dies verringert die Notwendigkeit, echo test | sudo tee /tmp/foo >/dev/nulldie Ausgabe zu verwerfen.
Adam Katz
2
Ich muss das vielleicht zurücknehmen; ddist dafür unzuverlässig, es sei denn, Sie verwenden obskure Nur-GNU-Optionen iflag=fullblock oflag=fullblock, die die Eleganz dieser Antwort aufheben. Ich bleibe dabei tee.
Adam Katz
5
dd ist zuverlässig mit dem nicht obskuren bs = 1
umeboshi
2
@umeboshi Aber zuverlässig nur, wenn Sie genug Erfahrung haben, um genau zu wissen, was Sie tun. Denn ddkann ziemlich gefährlich sein (wenn nicht zu sagen: verheerend), wenn nur ein kleiner Fehler gemacht wurde. Daher würde ich neuen Benutzern die teeMethode eher empfehlen , um an der sicheren Küste zu sein.
Syntaxfehler
1
@AdamKatz, im Falle von dd of=filealleine (ohne count/ skip...) ist es zuverlässig. iflag=fullblockwird nicht benötigt, da hier ddbei der Ausgabe das geschrieben wird, was es bei der Eingabe gelesen hat. Es ist egal, ob es nicht volle Blöcke waren.
Stéphane Chazelas
12

tee ist wahrscheinlich die beste Wahl, aber je nach Ihrer Situation kann Folgendes ausreichen:

sudo sh -c 'echo test > /tmp/foo'
phunehehe
quelle
1
3 Probleme: evalanstelle eines einfachen sh -c; -i, was dein Arbeitsverzeichnis ändert; Ausführen des gesamten Befehls als root, wodurch sich möglicherweise das Verhalten ändert oder ein unnötiges Risiko entsteht. Warum wurde das jemals positiv bewertet?
4
Das hast du nicht, aber es ist irreführend, im Allgemeinen schlecht und vielleicht sogar gefährlich.
5

Obwohl ich damit einverstanden bin, | sudo teeist das die kanonische Art und Weise, mit der sed (hier unter der Annahme von GNU sed) möglicherweise funktioniert:

cat sudotest 
line 1

sudo sed -i '1iitest' sudotest && cat sudotest 
itest
line 1

sudo sed -i '$aatest' sudotest && cat sudotest 
itest
line 1
atest

-iÄndert die vorhandene Datei. 1ibedeutet vor Zeile 1 einfügen . $abedeutet nach letzter Zeile anhängen .

Oder kopiere auf xclipboard:

somecommand | xclip
sudo gedit sudotest
move cursor to desired place, click middle mouse button to insert, save
Benutzer unbekannt
quelle
1
Dies ist wie ein altes chinesisches Rätsel formuliert. Ich kann nicht verstehen, wie das so viele positive Stimmen bekommen hat. ( hrmph )
Syntaxfehler
1
@syntaxerror: Sir, es tut mir leid, ich bin kein englischer Muttersprachler. Wenn Sie angeben, was für Sie unklar ist, könnte ich versuchen, meine Antwort zu verbessern. Verglichen mit 65 positiven Stimmen für Gert, scheint 4 auch nicht so viele positive Stimmen zu sein, findest du nicht?
Benutzer unbekannt
Naja ich wäre ziemlich zufrieden mit 4 :-D Dein Englisch ist überhaupt nicht schlecht. Es ist nur in einer Art knappen Techie Nerdspeak formuliert. Ich muss vermuten, dass Sie ein Kodierer sind. Codierer untereinander werden sich auf diese Weise perfekt verstehen, aber ein Nicht-Codierer muss denken, dass es so formuliert ist ... wie gesagt.
Syntaxfehler
Beachten Sie, dass sed -idie Datei nicht direkt geändert wird. Sie erstellt eine temporäre Datei und benennt sie beim Beenden um. Sie werden also nicht in der Lage sein, so etwas wie tail -f ...in der Originaldatei zu tun und die Ausgabe zu sehen, sed -i ...während die Pipeline läuft
Andrew Henle
@AndrewHenle: Ja, da die Größe möglicherweise vergrößert oder verkleinert wird und dies wahrscheinlich bei den meisten sed-Aufrufen der Fall ist und Sie auf SSDs nicht einmal an die gleiche Stelle schreiben können, handelt es sich nur um eine Pseudo-In-Place-Operation . Darf ich als nicht-englischer Muttersprachler um einen kurzen Ausdruck bitten, der wahrscheinlich nicht falsch interpretiert wird? Einfach -i creates a new file of same nameoder gibt es etwas kompakteres? Ich denke, ich mag in place, weil es das erklärt i. Die gnu-sed-Manpage nennt es ebenfalls " in place" und die lange Flagge ist "in" --in-place.
Benutzer unbekannt
2

Ich habe mir Gedanken über ein ähnliches Problem gemacht und die folgenden Lösungen gefunden:

  • sudo uncatWo uncatist ein Programm, das die Standardeingabe liest und in die in der Befehlszeile angegebene Datei schreibt, aber ich habe noch nicht geschrieben uncat.

  • sudocatdie variante davon sudoedithabe ich noch nicht geschrieben das macht einen sauberer sudo catoder sudo uncat.

  • oder dieser kleine Trick sudoeditmit einem EDITOR, der ein Shell-Skript ist

    #!/bin/sh
    # uncat
    cat > "$1"
    

    Das kann entweder als |sudo ./uncat fileoder aufgerufen werden | EDITOR=./uncat sudoedit, hat aber interessante Nebenwirkungen.

hildred
quelle
catnimmt eine Liste von Dateien con Katze inate daher uncat eine Liste von Dateien zu übernehmen sollte un con Katze inate zu. Es müsste Magie verwenden, um zu entscheiden, wie viel in jede Datei eingefügt werden soll. Alternative Namen umfassen dog, to-file, redirect.
Strg-Alt-Delor
Ich kann mir keinen Grund vorstellen, warum ich will, uncatwenn ich habe tee.
Wildcard
1
Nun, es teehat den kleinen Nachteil, dass es seine Standardeingabe in seine Standardeingabe schreibt - was trivial gemildert wird, indem die Standardeingabe in die Standardeingabe umgeleitet wird /dev/null. Andere Alternativen sind dd of=/tmp/foo(in einer anderen Antwort erwähnt), bei der Statusinformationen an stderr geschrieben werden, und cp /dev/stdin /tmp/foo.
Scott
1

Verwenden Sie einen Schwamm aus der moreutils-Packung. Es hat den Vorteil, dass es nicht nach stdout schreibt.

echo test | sudo sponge /tmp/foo

Verwenden Sie die Option -a, um eine Datei anzuhängen, anstatt sie zu überschreiben.

Hontvári Levente
quelle
1
Ich bin mir nicht sicher, welchen Vorteil es hat, nicht an Standardgeschenke zu schreiben, aber Sie könnten die Ausgabe einfach an umleiten, /dev/nullwenn es ein Problem wäre
Michael Mrozek
1
Natürlich kann ich nach / dev / null umleiten, aber der Befehl ist ohne die Umleitung einfacher zu lesen und zu tippen. Der Vorteil, nicht an stdout zu schreiben, ist, dass mein Terminal nicht mit Müll gefüllt ist.
Hontvári Levente
1
Ich würde kein Paket installieren, um eine Umleitung zu ersparen, aber ich verwende regelmäßig Schwamm, so ist es bereits da.
Hontvári Levente
0

Der Fehler kommt von der Reihenfolge, in der die Shell die Dinge tut.

Die Umleitung wird behandelt, bevor die Shell überhaupt ausgeführt wird sudo, und erfolgt daher mit den Berechtigungen des Benutzers, als dem Sie gerade arbeiten. Da Sie keine Schreibrechte zum Erstellen / Abschneiden des Umleitungsziels haben, permission deniedwird von der Shell eine Fehlermeldung ausgegeben.

Die Lösung besteht darin, sicherzustellen, dass die Ausgabedatei unter der Identität erstellt wird, die Sie erhalten sudo, z. B. mit tee:

$ generate_output | sudo tee target_file
Kusalananda
quelle