Piping STDERR vs. STDOUT

24

Gemäß " Linux: The Complete Reference 6th Edition " (S. 44) können Sie mit den Umleitungssymbolen nur STDERR |&umleiten.

Ich habe ein ziemlich einfaches Skript geschrieben, um dies zu testen:

#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2

Ich führe dieses Skript folgendermaßen aus:

./script.sh |& sed 's:^:\t:'

Vermutlich werden nur die in STDERR gedruckten Zeilen eingerückt. Allerdings funktioniert es nicht wirklich so, wie ich sehe:

    Normal Text.
    Error Text. 

Was mache ich hier falsch?

Naftuli Kay
quelle

Antworten:

26

Ich weiß nicht, welchen Text Ihr Buch verwendet, aber das Bash-Handbuch ist klar (wenn Sie mit Weiterleitungen bereits ein wenig vertraut sind):

Wenn |&verwendet, wird der Standardfehler von Befehl1 zusätzlich zu seiner Standardausgabe über die Pipe mit dem Standardeingang von Befehl2 verbunden. es ist eine Abkürzung für 2>&1 |. Diese implizite Umleitung des Standardfehlers zur Standardausgabe erfolgt nach allen vom Befehl angegebenen Umleitungen.

Wenn Sie also Standardausgabe und Standardfehler nicht mischen möchten, müssen Sie die Standardausgabe an eine andere Stelle umleiten. Siehe Standardfehlerdatenstrom (stderr) abrufen.

{ ./script.sh 2>&1 >&3 | sed 's:^:\t:'; } 3>&1

Sowohl fd 1 als auch 3 von script.shund sedzeigen jedoch auf das ursprüngliche Standardziel. Wenn Sie ein guter Bürger sein wollen, können Sie jenes fd 3 schließen, das diese Befehle nicht benötigen:

{ ./script.sh 2>&1 >&3 3>&- | sed 's:^:\t:' 3>&-; } 3>&1

bashund ksh93kann die >&3 3>&-zu verdichten >&3-(fd move).

Gilles 'SO - hör auf böse zu sein'
quelle
Das Bash-Handbuch ist mir nicht ganz klar. Ich verstehe nicht ganz, warum smth like ./script.sh > /tmp/stdout_goes_here |& grep 'grepping_script_stderr'nicht wie vorgesehen funktioniert, dh: redirect script.sh's stdout(was laut manuellem Snippet zuerst passieren sollte), dann erlauben grep, die Skripte zu verarbeiten stderr. Stattdessen stderrund tdout` landen beide stdout_goes_here
sxc731
1
@ sxc731 |&ist kurzsichtig für 2>&1 |. So >/tmp/stdout_goes_here |&Umleitungen an stdout /tmp/stdout_goes_here, dann 2>&1leitet stderr an , wohin stdout geht ist, was ist /tmp/stdout_goes_here, und schließlich |erhält keine Eingabe , da die Ausgabe des Befehls umgeleitet wurde. Denken Sie daran, dass die >&1Weiterleitung an den Speicherort von Dateideskriptor 1 erfolgt und nicht an den Speicherort von Dateideskriptor 1 . Eine Möglichkeit ist, nur stderr zu leiten und stdout in eine Datei umzuleiten 2>&1 >/tmp/stdout_goes_here |.
Gilles 'SO - hör auf böse zu sein'
6

|&Pipes stderr nach stdin, 2>&1 |also wird das nächste Programm beide auf stdin bekommen.

$cat test.sh
#!/bin/bash
echo "Normal Text."
echo "Error Text." >&2
$./test.sh | sed 's:^:\t:'
Error Text.
        Normal Text.
$ ./test.sh |& sed 's:^:\t:'
        Normal Text.
        Error Text.
Kevin
quelle
Oh, also ist es im Grunde gleichbedeutend mit dem längeren Ausdruck runcommand 2>&1 | tee? dh runcommand |& tee?
Naftuli Kay
Ja, sie sind die gleichen.
Kevin
1

|&in bash ist nur eine (nicht fürchterlich tragbare) Abkürzung für 2>&1 |, daher sollte jede Zeile eingerückt sein.

jw013
quelle