Ich habe heute versucht, beide stdout
und stderr
zu einer Datei umzuleiten , und dabei bin ich auf Folgendes gestoßen:
<command> > file.txt 2>&1
Diese leitet offenbar stderr
auf den stdout
ersten und dann die resultierende stdout
wird umgeleitet file.txt
.
Warum ist die Bestellung jedoch nicht gültig <command> 2>&1 > file.txt
? Man würde dies natürlich so lesen (unter der Annahme, dass der Befehl von links nach rechts ausgeführt wird), dass er zuerst ausgeführt wird, stderr
dass er umgeleitet wird stdout
und dann, dass stdout
er geschrieben wird file.txt
. Die oben genannten Optionen leiten jedoch nur stderr
zum Bildschirm weiter.
Wie interpretiert die Shell beide Befehle?
command-line
bash
redirect
Herznetz trainieren
quelle
quelle
bash
Handbuch . Weiterleitungen sind übrigens keine Befehle.execv
Systemaufruf -family aufgerufen wird, um den Unterprozess tatsächlich an den zu startenden Befehl weiterzuleiten, ist die Shell nicht mehr in der Schleife (in diesem Prozess wird kein Code mehr ausgeführt) ) und hat keine Möglichkeit zu kontrollieren, was von diesem Zeitpunkt an geschieht; Umleitungen müssen daher alle ausgeführt werden, bevor die Ausführung beginnt, während auf der Shell eine Kopie von sich selbst in dem Prozess ausgeführt wird, in dem siefork()
Ihren BefehlAntworten:
Wenn Sie
<command> 2>&1 > file.txt
stderr ausführen2>&1
, wird Ihr Terminal umgeleitet . Danach wird stdout von in die Datei umgeleitet>
, aber stderr wird nicht mit dieser umgeleitet, bleibt also als Terminalausgabe.Mit
<command> > file.txt 2>&1
stdout wird zuerst in die Datei umgeleitet>
, dann wird2>&1
stderr dorthin umgeleitet, wohin stdout geht, welches die Datei ist.Es mag zunächst als nicht intuitiv erscheinen, aber wenn Sie sich die Umleitungen auf diese Weise vorstellen und sich daran erinnern, dass sie von links nach rechts verarbeitet werden, ist dies viel sinnvoller.
quelle
Es könnte sinnvoll sein, wenn Sie es ausfindig machen.
Am Anfang gehen stderr und stdout auf dasselbe (normalerweise das Terminal, das ich hier nenne
pts
):Ich beziehe mich hier auf stdin, stdout und stderr durch ihre Dateideskriptornummern : sie sind Dateideskriptoren 0, 1 bzw. 2.
In der ersten Umleitung haben wir
> file.txt
und2>&1
.So:
> file.txt
:fd/1
geht jetzt zufile.txt
. Mit>
,1
ist der implizite Dateideskriptor, wenn nichts angegeben ist. Dies ist also1>file.txt
:2>&1
:fd/2
Jetzt geht es dorthin, wohinfd/1
gerade :Andererseits mit
2>&1 > file.txt
umgekehrter Reihenfolge:2>&1
:fd/2
Jetzt geht es dorthin, wohin esfd/1
gerade geht, was bedeutet, dass sich nichts ändert:> file.txt
:fd/1
jetzt geht anfile.txt
:Der wichtige Punkt ist, dass Umleitung nicht bedeutet, dass der umgeleitete Dateideskriptor allen zukünftigen Änderungen am Zieldateideskriptor folgt. es wird nur den aktuellen Zustand annehmen .
quelle
2.
im zweiten Teil einen kleinen Tippfehler gemacht ;fd/1 -> file.txt
und nichtfd/2 -> file.txt
.Ich denke, es hilft zu denken, dass die Shell zuerst die Umleitung auf der linken Seite einrichtet und sie abschließt , bevor die nächste Umleitung eingerichtet wird.
Die Linux Command Line von William Shotts sagt
das macht aber dann sinn
Tatsächlich können wir stdout nach stderr umleiten, nachdem stderr in eine Datei mit dem gleichen Effekt umgeleitet wurde
In
command > file 2>&1
diesem Fall sendet die Shell stdout an eine Datei und sendet dann stderr an stdout (das an eine Datei gesendet wird). Während incommand 2>&1 > file
der Shell zuerst stderr zu stdout umleitet (dh im Terminal anzeigt, wohin stdout normalerweise geht) und anschließend stdout in die Datei umleitet. TLCL führt in die Irre, dass wir stdout zuerst umleiten müssen: da wir stderr zuerst in eine Datei umleiten und dann stdout dorthin senden können. Was wir nicht tun können, ist stdout nach stderr umzuleiten oder umgekehrt, bevor in eine Datei umgeleitet wird. Ein anderes BeispielWir denken vielleicht, dies würde stdout an die gleiche Stelle wie stderr bringen, aber das tut es nicht, es leitet stdout zuerst an stderr (den Bildschirm) weiter und leitet dann nur stderr weiter, als wenn wir es andersherum versucht hätten ...
Ich hoffe das bringt ein bisschen Licht ...
quelle
Sie haben bereits einige sehr gute Antworten erhalten. Lassen Sie mich jedoch betonen, dass es sich um zwei verschiedene Konzepte handelt, deren Verständnis enorm hilft:
Hintergrund: Dateideskriptor vs. Dateitabelle
Ihr Dateideskriptor ist nur eine Zahl 0 ... n, der Index in der Dateideskriptortabelle in Ihrem Prozess. Gemäß Konvention ist STDIN = 0, STDOUT = 1, STDERR = 2 (beachten Sie, dass die Begriffe
STDIN
usw. hier nur Symbole / Makros sind , die gemäß Konvention in einigen Programmiersprachen und Manpages verwendet werden; es gibt kein aktuelles "Objekt" mit dem Namen STDIN; z der Zweck dieser Diskussion, STDIN ist 0, etc.).Diese Dateideskriptortabelle selbst enthält keinerlei Informationen darüber, was die eigentliche Datei ist. Stattdessen enthält es einen Zeiger auf eine andere Dateitabelle. Letzteres enthält Informationen zu einer tatsächlichen physischen Datei (oder einem Blockgerät oder einer Pipe oder was auch immer Linux über den Dateimechanismus adressieren kann) und weitere Informationen (z. B. ob es zum Lesen oder Schreiben dient).
Wenn Sie also
>
oder<
in Ihrer Shell verwenden, ersetzen Sie einfach den Zeiger des jeweiligen Dateideskriptors, um auf etwas anderes zu verweisen. Die Syntax zeigt2>&1
einfach Deskriptor 2 auf 1 Punkt.> file.txt
öffnet sich einfachfile.txt
zum Schreiben und lässt STDOUT (Datei-Decsriptor 1) darauf verweisen.Es gibt andere Extras, z. B
2>(xxx)
.: Erstellen eines neuen Prozessesxxx
, Erstellen einer Pipe, Verbinden des Dateideskriptors 0 des neuen Prozesses mit dem Leseende der Pipe und Verbinden des Dateideskriptors 2 des ursprünglichen Prozesses mit dem Schreibende der Pipe Rohr).Dies ist auch die Grundlage für "Datei-Handle-Magie" in einer anderen Software als Ihrer Shell. Beispielsweise können Sie in Ihrem Perl-Skript
dup
den STDOUT-Dateideskriptor in einen anderen (temporären) Deskriptor zerlegen und dann STDOUT erneut in einer neu erstellten temporären Datei öffnen. Ab diesem Zeitpunkt werden alle STDOUT-Ausgaben Ihres eigenen Perl-Skripts und allesystem()
Aufrufe dieses Skripts in dieser temporären Datei gespeichert. Wenn Sie fertig sind, können Siedup
Ihr STDOUT auf den temporären Deskriptor zurücksetzen, in dem Sie es gespeichert haben, und außerdem ist alles wie zuvor. Sie können in der Zwischenzeit sogar in diesen temporären Deskriptor schreiben. Während also Ihre aktuelle STDOUT-Ausgabe in die temporäre Datei verschoben wird, können Sie tatsächlich noch Daten in das echte STDOUT ausgeben (normalerweise der Benutzer).Antworten
So wenden Sie die oben angegebenen Hintergrundinformationen auf Ihre Frage an:
Links nach rechts.
fork
aus einem neuen Prozess.file.txt
und speichern Sie den Zeiger im Dateideskriptor 1 (STDOUT).file.txt
natürlich wieder der bereits geöffnete ist ).exec
das<command>
Dies wäre sinnvoll, wenn es nur eine Tabelle gäbe , aber wie oben erläutert, gibt es zwei. Dateideskriptoren verweisen nicht rekursiv aufeinander. Es macht keinen Sinn, "STDERR zu STDOUT umleiten". Der richtige Gedanke ist "point STDERR to wherever STDOUT points". Wenn Sie STDOUT später ändern, bleibt STDERR dort, wo es ist. Weitere Änderungen an STDOUT werden nicht auf magische Weise übernommen.
quelle
Die Reihenfolge ist von links nach rechts. Bashs Handbuch hat bereits Ihre Fragen beantwortet. Zitat aus dem
REDIRECTION
Abschnitt des Handbuchs:und ein paar Zeilen später:
Es ist wichtig zu beachten, dass die Umleitung zuerst aufgelöst wird, bevor Befehle ausgeführt werden! Siehe https://askubuntu.com/a/728386/295286
quelle
Es ist immer von links nach rechts ... außer wenn
Genau wie in Mathe verfahren wir von links nach rechts, mit der Ausnahme, dass die Multiplikation und Division vor der Addition und Subtraktion erfolgt, mit der Ausnahme, dass Operationen in Klammern (+ -) vor der Multiplikation und Division erfolgen.
Gemäß der Anleitung für Bash-Anfänger hier (Anleitung für Bash-Anfänger ) gibt es 8 Hierarchiestufen für das, was zuerst kommt (von links nach rechts):
Es ist also immer von links nach rechts ... außer wenn ...
quelle