Wie verwende ich sudo, um die Ausgabe an einen Ort umzuleiten, an den ich keine Schreibberechtigung habe?

881

Ich habe Sudo-Zugriff auf eine unserer RedHat-Linux-Entwicklungsboxen erhalten, und es scheint, dass ich ziemlich oft die Ausgabe an einen Ort umleiten muss, auf den ich normalerweise keinen Schreibzugriff habe.

Das Problem ist, dass dieses erfundene Beispiel nicht funktioniert:

sudo ls -hal /root/ > /root/test.out

Ich erhalte gerade die Antwort:

-bash: /root/test.out: Permission denied

Wie kann ich das zum Laufen bringen?

Jonathan
quelle
1
benutze chmod u + w Dateiname
Szabolcs Dombi
@DombiSzabolcs Sie schlagen vor, dass ich die Datei zuerst als sudo erstelle und mir dann die Erlaubnis gebe? Gute Idee.
Jonathan
In vielen Situationen landen Sie hier, weil Sie gefragt haben: "Warum wird mir die Berechtigung verweigert?" Manchmal ist die Antwort, dass Sie eine Datei erstellen müssen als root(in diesem Fall lesen Sie die Antworten), aber sehr oft müssen Sie die Datei einfach woanders erstellen, wie Sie selbst.
Tripleee
1
Nachdem ich mit diesen Antworten zu kämpfen habe, entscheide ich mich schließlich, zu einer temporären Datei umzuleiten und sie an das Ziel zu verschieben.
TingQian LI
Siehe auch stackoverflow.com/questions/84882/…
Nate Eldredge

Antworten:

1233

Ihr Befehl funktioniert nicht, da die Umleitung von Ihrer Shell ausgeführt wird, die nicht zum Schreiben berechtigt ist /root/test.out. Die Umleitung der Ausgabe wird nicht von sudo durchgeführt.

Es gibt mehrere Lösungen:

  • Führen Sie eine Shell mit sudo aus und geben Sie den Befehl mit der folgenden -cOption ein:

    sudo sh -c 'ls -hal /root/ > /root/test.out'
    
  • Erstellen Sie ein Skript mit Ihren Befehlen und führen Sie dieses Skript mit sudo aus:

    #!/bin/sh
    ls -hal /root/ > /root/test.out
    

    Ausführen sudo ls.sh. Siehe Steve Bennetts Antwort, wenn Sie keine temporäre Datei erstellen möchten.

  • Starten Sie eine Shell mit sudo -sund führen Sie dann Ihre Befehle aus:

    [nobody@so]$ sudo -s
    [root@so]# ls -hal /root/ > /root/test.out
    [root@so]# ^D
    [nobody@so]$
    
  • Verwenden Sie sudo tee(wenn Sie bei Verwendung der -cOption viel entkommen müssen ):

    sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null
    

    Die Umleitung zu /dev/nullwird benötigt, um zu verhindern, dass das T-Stück auf dem Bildschirm ausgegeben wird. Um anhängen , anstatt die Ausgabedatei überschreiben ( >>), die Verwendung tee -aoder tee --append(die letzte ist spezifisch für GNU coreutils ).

Vielen Dank an Jd , Adam J. Forster und Johnathan für die zweite, dritte und vierte Lösung.

Cristian Ciupitu
quelle
1
Es gibt eine großartige Antwort, die Ihnen sagt, wie Sie STDERR und STDOUT hier separat umleiten können: stackoverflow.com/questions/692000/… ... im Grunde genommenperl -e 'print "STDIN\n"; print STDERR "STDERR\n"; ' > >( tee stdout.log ) 2> >( tee stderr.log >&2 )
errant.info
2
Sie sollten 'sudo -E ...' ausführen, um Variablen im Befehl shelled out zu verwenden (wenn Sie dies beispielsweise in einem Skript verwenden).
Urhixidur
3
Das Umleiten der Tee-Ausgabe nach / dev / null ist wahrscheinlich in vielen Fällen nicht erforderlich, in denen das Echo der Ausgabe auf den Bildschirm harmlos ist. Zum Beispiel, wenn es nur um die Ausgabe regulärer Befehle oder den Inhalt kleiner Textdateien geht.
Thomasrutter
105

Jemand hier hat gerade vorgeschlagen, sudoing Tee:

sudo ls -hal /root/ | sudo tee /root/test.out > /dev/null

Dies kann auch verwendet werden, um einen Befehl in ein Verzeichnis umzuleiten, auf das Sie keinen Zugriff haben. Es funktioniert, weil das Tee-Programm effektiv ein "Echo to a File" -Programm ist und die Umleitung zu / dev / null verhindert, dass es auch auf dem Bildschirm ausgegeben wird, damit es das gleiche wie das oben erfundene Beispiel bleibt.

Jonathan
quelle
5
In vielen Fällen, nämlich wenn der normale Benutzer Berechtigungen zum Ausführen des Befehls hat und "nur" nicht in die gewünschte Ausgabedatei schreiben kann, kann die erste sudo(dh für den Befehl selbst) weggelassen werden
Hagen von Eitzen
81

Ein Trick, den ich selbst herausgefunden habe, war

sudo ls -hal /root/ | sudo dd of=/root/test.out
rhlee
quelle
16
sudo ddist besser als die sudo tee /root/file > /dev/nullobigen Beispiele!
Kristianlm
14
dd ist kein seltsamer obskurer Befehl. Es wird immer dann verwendet, wenn Sie große Datenmengen mit Pufferung zwischen zwei Blockgeräten kopieren müssen. Die Syntax ist eigentlich ziemlich einfach, ddist der Befehlsname, of=/root/test.outist das Argument, das angibt, ddwas die Ausgabedateien sind.
Rhlee
14
@steve Alles ist "dunkel", bis Sie lernen, was es ist. ofbedeutet Ausgabedatei und ddist ein sehr beliebtes Tool, das sowohl unter Linux als auch unter OSX verwendet wird (hauptsächlich zum Schreiben von Bildern auf Datenträger). Dies ist sicher ein ordentlicher Trick.
Blockloop
12
ddist wahrscheinlich genauso nützlich wie teehier. In beiden Fällen verwenden Sie einen allgemeinen, bekannten Befehl für einen Zweck, der zwar geringfügig vom ursprünglich vorgesehenen Zweck abweicht, aber dennoch bekannt und gut dokumentiert ist. Während ddes gut darin ist, große Datenmengen zu kopieren, saugt es nicht mit kleinen Mengen. Dies hat den Vorteil, dass die Ausgabe nicht auch auf die Standardausgabe zurückgeführt wird.
Thomasrutter
26
Wenn Sie Wörter sudo ddnebeneinander eingeben, möchten Sie sehr, sehr sicher gehen, dass die folgenden Argumente korrekt sind (insbesondere unter Berücksichtigung der nicht standardmäßigen Syntax). Sie nennen es nicht umsonst "Disk Destroyer" ...
ali_m
45

Das Problem ist, dass der Befehl unter ausgeführt sudowird, die Umleitung jedoch unter Ihrem Benutzer ausgeführt wird. Dies geschieht durch die Shell und es gibt sehr wenig, was Sie dagegen tun können.

sudo command > /some/file.log
`-----v-----'`-------v-------'
   command       redirection

Die üblichen Möglichkeiten, dies zu umgehen, sind:

  • Schließen Sie die Befehle in ein Skript ein, das Sie unter sudo aufrufen.

    Wenn sich die Befehle und / oder die Protokolldatei ändern, können Sie das Skript veranlassen, diese als Argumente zu verwenden. Zum Beispiel:

    sudo log_script command /log/file.txt
    
  • Rufen Sie eine Shell auf und übergeben Sie die Befehlszeile als Parameter mit -c

    Dies ist besonders nützlich für einmalige zusammengesetzte Befehle. Zum Beispiel:

    sudo bash -c "{ command1 arg; command2 arg; } > /log/file.txt"
    
dsm
quelle
23

Noch eine Variation des Themas:

sudo bash <<EOF
ls -hal /root/ > /root/test.out
EOF

Oder natürlich:

echo 'ls -hal /root/ > /root/test.out' | sudo bash

Sie haben den (winzigen) Vorteil, dass Sie sich keine Argumente für sudooder sh/ merken müssenbash

Steve Bennett
quelle
18

Klären Sie ein wenig, warum die Tee-Option vorzuziehen ist

Angenommen, Sie haben die entsprechende Berechtigung zum Ausführen des Befehls, mit dem die Ausgabe erstellt wird. Wenn Sie die Ausgabe Ihres Befehls an tee weiterleiten, müssen Sie nur die Berechtigungen von tee mit sudo erhöhen und tee direkt an die betreffende Datei schreiben (oder anhängen).

in dem Beispiel in der Frage würde das bedeuten:

ls -hal /root/ | sudo tee /root/test.out

für ein paar weitere praktische Beispiele:

# kill off one source of annoying advertisements
echo 127.0.0.1 ad.doubleclick.net | sudo tee -a /etc/hosts

# configure eth4 to come up on boot, set IP and netmask (centos 6.4)
echo -e "ONBOOT=\"YES\"\nIPADDR=10.42.84.168\nPREFIX=24" | sudo tee -a /etc/sysconfig/network-scripts/ifcfg-eth4

In jedem dieser Beispiele nehmen Sie die Ausgabe eines nicht privilegierten Befehls und schreiben in eine Datei, die normalerweise nur von root geschrieben werden kann. Dies ist der Ursprung Ihrer Frage.

Es ist eine gute Idee, dies auf diese Weise zu tun, da der Befehl, der die Ausgabe generiert, nicht mit erhöhten Berechtigungen ausgeführt wird. Es scheint hier keine Rolle zu spielen, echoaber wenn der Quellbefehl ein Skript ist, dem Sie nicht vollständig vertrauen, ist es entscheidend.

Beachten Sie, dass Sie die Option -a verwenden können, um das Anhängen (Gefällt mir >>) an die Zieldatei anzuhängen, anstatt sie zu überschreiben ( Gefällt mir >).

jg3
quelle
Sorry js3, aber dies wurde bereits vorgeschlagen (im Jahr 2008) und sitzt bei der zweithöchsten Antwort: stackoverflow.com/a/82553/6910
Jonathan
2
Sie haben Recht, Jonathan, ich werde meine Antwort aktualisieren, um die Gründe zu erläutern, warum dies eine bevorzugte Option ist. Vielen Dank für das hilfreiche Feedback.
jg3
17

Lassen Sie sudo eine Shell wie folgt ausführen:

sudo sh -c "echo foo > ~root/out"
Penfold
quelle
11

Die Art und Weise, wie ich dieses Problem angehen würde, ist:

Wenn Sie die Datei schreiben / ersetzen müssen:

echo "some text" | sudo tee /path/to/file

Wenn Sie an die Datei anhängen müssen:

echo "some text" | sudo tee -a /path/to/file
Nikola Petkanski
quelle
1
Wie unterscheidet sich dies wesentlich von den obigen Antworten?
Jonathan
2
Es ist nicht "wesentlich anders", aber es verdeutlicht die unterschiedliche Verwendung zwischen Ersetzen und Anhängen an die Datei.
Jamadagni
1
Dies ist die Antwort, die ich auf meinen Spickzettel kopiert habe.
MortimerCat
5

Wie wäre es mit einem Skript?

Dateiname: Myscript

#!/bin/sh

/bin/ls -lah /root > /root/test.out

# end script

Verwenden Sie dann sudo, um das Skript auszuführen:

sudo ./myscript

quelle
4

Wann immer ich so etwas tun muss, werde ich einfach Wurzel:

# sudo -s
# ls -hal /root/ > /root/test.out
# exit

Es ist wahrscheinlich nicht der beste Weg, aber es funktioniert.

Adam J. Forster
quelle
4

Ich würde es so machen:

sudo su -c 'ls -hal /root/ > /root/test.out'
Fardjad
quelle
2
Das scheint tatsächlich etwas sauberer zu sein, da Sie die Shell nicht explizit angeben müssen.
Steve Bennett
1
Ein kleiner Nachteil ist, dass es einen zusätzlichen Prozess su$ sudo su -c 'pstree -sp $$ >/dev/fd/1' init(1)───gnome-terminal(6880)───bash(6945)───sudo(401)───su(402)───bash(410)───pstree(411)
ausführt
3

Sie wollen kein totes Pferd schlagen, aber es gibt zu viele Antworten tee, die Sie verwenden. Dies bedeutet stdout, /dev/nulldass Sie umleiten müssen , es sei denn, Sie möchten eine Kopie auf dem Bildschirm sehen.

Eine einfachere Lösung besteht darin, einfach Folgendes zu verwenden cat:

sudo ls -hal /root/ | sudo bash -c "cat > /root/test.out"

Beachten Sie, wie die Umleitung in Anführungszeichen gesetzt wird, damit sie von einer Shell ausgewertet wird, die von gestartet wird, sudoanstatt von der, auf der sie ausgeführt wird.

haridsv
quelle
Das funktioniert gut. Ich verstehe nicht, warum es eine negative Stimme gab. Upvoted.
Teemu Leisti
4
Ich denke, es wird nicht viel geliebt, weil es nicht viel besser ist als sudo bash -c "ls -hal /root > /root/test.out". Durch die Verwendung von Tee wird vermieden, dass eine Muschel benötigt wird, während dies bei Katzen nicht der Fall ist.
Nick Russo
2

Dies basiert auf der Antwort mit tee. Um die Sache zu vereinfachen, habe ich ein kleines Skript geschrieben (ich nenne es suwrite) und es /usr/local/bin/mit +xErlaubnis eingefügt:

#! /bin/sh
if [ $# = 0 ] ; then
    echo "USAGE: <command writing to stdout> | suwrite [-a] <output file 1> ..." >&2
    exit 1
fi
for arg in "$@" ; do
    if [ ${arg#/dev/} != ${arg} ] ; then
        echo "Found dangerous argument ‘$arg’. Will exit."
        exit 2
    fi
done
sudo tee "$@" > /dev/null

Wie in der VERWENDUNG im Code gezeigt, müssen Sie lediglich die Ausgabe an dieses Skript weiterleiten, gefolgt vom gewünschten Dateinamen, auf den der Superuser zugreifen kann, und Sie werden bei Bedarf automatisch zur Eingabe Ihres Kennworts aufgefordert (da es enthält sudo).

echo test | suwrite /root/test.txt

Da dies ein einfacher Wrapper für ist tee, wird auch die -aOption zum Anhängen von tees akzeptiert und das gleichzeitige Schreiben in mehrere Dateien unterstützt.

echo test2 | suwrite -a /root/test.txt
echo test-multi | suwrite /root/test-a.txt /root/test-b.txt

Es bietet auch einen vereinfachten Schutz gegen das Schreiben auf /dev/Geräte, der in einem der Kommentare auf dieser Seite erwähnt wurde.

Jamadagni
quelle
1

Vielleicht haben Sie Sudo nur Zugriff auf einige Programme / Pfade erhalten? Dann gibt es keine Möglichkeit zu tun, was Sie wollen. (es sei denn, Sie werden es irgendwie hacken)

Wenn dies nicht der Fall ist, können Sie möglicherweise ein Bash-Skript schreiben:

cat > myscript.sh
#!/bin/sh
ls -hal /root/ > /root/test.out 

Drücken Sie ctrl+ d:

chmod a+x myscript.sh
sudo myscript.sh

Hoffe es hilft.

user15453
quelle
1
sudo at now  
at> echo test > /tmp/test.out  
at> <EOT>  
job 1 at Thu Sep 21 10:49:00 2017  
user8648126
quelle
1
Wenn Sie sudosowieso haben, atist nicht nützlich oder notwendig. sudo sh -c 'echo test >/tmp/test.out'macht das gleiche viel effizienter und eleganter (leidet aber immer noch unter dem Fehler, dass Sie wahrscheinlich Dinge rootausführen, die dieses Privileg nicht benötigen; Sie sollten privilegierte Befehle generell vermeiden, wenn Sie können).
Tripleee