Wie kann ich mit bash Standardfehler in einen anderen Prozess leiten?

137

Es ist bekannt, wie die Standardausgabe eines Prozesses in die Standardeingabe eines anderen Prozesses geleitet wird:

proc1 | proc2

Was aber, wenn ich den Standardfehler von proc1 an proc2 senden und die Standardausgabe an ihrem aktuellen Speicherort belassen möchte? Sie würden denken, bashhätte einen Befehl in der Art von:

proc1 2| proc2

Aber leider nein. Gibt es eine Möglichkeit, dies zu tun?

paxdiablo
quelle
Sie können eine so einfache Umleitung in einer rcanderen Shell durchführen. ZB : proc1 |[2] proc2. Ist es nicht schön Aber nicht bashdrin.
Rolf

Antworten:

168

Es gibt auch eine Prozessersetzung . Dadurch wird ein Prozess durch eine Datei ersetzt.
Sie können stderrwie folgt an eine Datei senden :

process1 2> file

Sie können die Datei jedoch wie folgt durch einen Prozess ersetzen:

process1 2> >(process2)

Hier ist ein konkretes Beispiel, das stderrsowohl an den Bildschirm gesendet als auch an eine Protokolldatei angehängt wird

sh myscript 2> >(tee -a errlog)
Schotte
quelle
23
Dies beantwortet die angegebene Frage richtig und sollte die akzeptierte Antwort von @paxdiablo
mmlb
Ich habe es versucht. Es hat nicht funktioniert ( weston --help 2> >(less)), und es hat meine Muschel gebrochen, ich musste gehen und mich wieder einloggen.
Rolf
1
@Rolf Wenn beide weston --helpund lesseine Tastaturinteraktion erwarten, aber nur einer von ihnen diese empfängt, befinden Sie sich möglicherweise in einer unangenehmen Situation. Versuchen Sie grepstattdessen, mit so etwas zu testen . Außerdem stellen Sie möglicherweise fest, dass beide Maus- / Tastatureingaben ohnehin zum 2. Befehl und nicht zu Weston gehen.
BeowulfNode42
88

Sie können den folgenden Trick verwenden, um stdout und zu tauschenstderr . Dann verwenden Sie einfach die reguläre Pipe-Funktionalität.

( proc1 3>&1 1>&2- 2>&3- ) | proc2

Vorausgesetzt , stdoutund stderrbeide an der gleichen Stelle am Anfang darauf, dies wird dir geben , was Sie brauchen.

Das x>yBit ändert das Dateihandle, xsodass es seine Informationen jetzt an die Stelle sendet, auf die das Dateihandle yderzeit zeigt. Für unseren speziellen Fall:

  • 3>&1Erstellt ein neues Handle, 3das in das aktuelle Handle 1(ursprüngliches Standardout) ausgegeben wird , um es irgendwo für den letzten Aufzählungspunkt unten zu speichern.
  • 1>&2Ändert das Handle 1(stdout), um es an das aktuelle Handle 2(original stderr) auszugeben .
  • 2>&3-Ändert das Handle 2(stderr), um es an das aktuelle Handle 3(ursprüngliches stdout) auszugeben, und schließt dann das Handle 3(über das -am Ende).

Es ist effektiv der Swap-Befehl, den Sie in Sortieralgorithmen sehen:

temp   = value1;
value1 = value2;
value2 = temp;
paxdiablo
quelle
3
Was ist der Wert der Verwendung 1>&2-hier und nicht nur 1>&2? Ich verstehe nicht, warum wir fd schließen wollen 2, wenn wir es nur sofort wieder öffnen / neu zuweisen.
Dubiousjim
1
@dubiousjim, kein Vorteil in diesem speziellen Fall, ich vermute, ich habe es nur getan, um konsistent zu sein - das Schließen von Dateihandle 3 ist eine gute Idee, um es freizugeben.
Paxdiablo
Guter Punkt, @ovgolovin, ich kann nicht glauben, dass niemand das in sieben Monaten aufgegriffen hat, seit ich diese Bearbeitung vorgenommen habe. Nach Ihrem Vorschlag behoben.
Paxdiablo
versuchen, gccs make (das auf meinem System eingefärbt ist) dazu zu bringen, mit diesem "(make 3> & 1 1> & 2- 2> & 3-) | less -R" zu arbeiten, während "(ls -al 3> & 1 1> & 2- 2> & 3-) | less -R "funktioniert wie erwartet.
synchronisiert
Anscheinend sind Ihre Erklärungen für die zweiten beiden Weiterleitungen von hinten nach vorne. 1> & 2- Setzt das Dateihandle 2 (Original-Stderr) auf 1 (Original-Stdout). 2> & 3- Setzt das Datei-Handle 3 (kopiertes Stdout) auf Handle 2 (Original-Stderr). Bitte korrigieren Sie mich, wenn ich falsch liege. Übrigens würde ich vermuten, dass der Bindestrich auf 2 verhindern soll, dass neue stderr-Daten an diesen Puffer gesendet werden, während sie mit den Daten von stdout gefüllt werden.
Aghsmith
70

Bash 4 hat diese Funktion:

Wenn "| &" verwendet wird, wird der Standardfehler von Befehl1 über die Pipe mit der Standardeingabe von Befehl2 verbunden. es ist eine Abkürzung für 2> & 1 |. Diese implizite Umleitung des Standardfehlers wird nach allen durch den Befehl angegebenen Umleitungen ausgeführt.

zsh hat auch diese Funktion.

- -

Bei anderen / älteren Shells geben Sie dies einfach explizit als ein

Erster Befehl 2> & 1 | OtherCommand

Bis auf weiteres angehalten.
quelle
14
Beim Lesen der Dokumente werden sowohl Standardfehler als auch Ausgaben im Gegensatz zu nur stderr ausgeführt, aber es ist schön zu wissen. Es ist Zeit, sich Bash 4 anzuschauen, denke ich.
Paxdiablo
Das aktuelle Bash-Handbuch lautet "Wenn | & verwendet wird, wird der Standardfehler des Befehls zusätzlich zu seiner Standardausgabe mit der Standardeingabe von Befehl2 verbunden". Dies ist ausdrücklich nicht das, was das OP will.
Peter - Monica am
@ PeterA.Schneider: Das OP sagt "Belassen Sie die Standardausgabe an ihrem aktuellen Speicherort", was möglicherweise nicht eindeutig ist.
Bis auf weiteres angehalten.
Ich sehe keine Mehrdeutigkeit. Ihr Vorschlag (1) bringt die beiden Ströme zusammen. (2) OtherCommandschreibt die kombinierten Daten irgendwo, möglicherweise woanders. Es sind also nicht die gleichen Daten, und sie gehen möglicherweise woanders hin. Das ist ungefähr das Gegenteil des Wunsches des OP, nicht wahr?
Peter - Monica am
@ PeterA.Schneider: Wo sonst befindet sich der aktuelle Standort der Standardausgabe? Wenn proc1Ausgaben an stdout und an stderr ausgegeben werden und Sie möchten, dass stderr zum stdin von geht proc2(wo sich das stdout von proc1 befindet), dann erreicht meine Antwort dies. Ich gab dem OP, worum er bat , vielleicht nicht, was er wollte . Darin liegt die potentielle Mehrdeutigkeit. Die OP akzeptiert die Antwort , die Swaps stdout und stderr das ist nicht , was er verlangte.
Bis auf weiteres angehalten.
27

Tauschen ist großartig, da es das Problem löst. Nur für den Fall, dass Sie nicht einmal das Original-Standard benötigen, können Sie dies folgendermaßen tun:

proc1 2>&1 1>/dev/null | proc2

Die Reihenfolge ist wichtig; du würdest nicht wollen:

proc1 >/dev/null 2>&1 | proc1

Da dies alles umleiten wird /dev/null!

kccqzy
quelle
0

Keines davon hat wirklich sehr gut funktioniert. Der beste Weg, das zu tun, was Sie wollten, ist:

(command < input > output) 2>&1 | less

Dies funktioniert nur in Fällen, in denen commandkeine Tastatureingabe erforderlich ist. z.B:

(gzip -d < file.gz > file) 2>&1 | less

würde gzip Fehler in weniger setzen

sbingner
quelle