Tubazioni STDERR vs. STDOUT


24

Secondo " Linux: The Complete Reference 6th Edition " (pag. 44), è possibile reindirizzare solo STDERR utilizzando i |&simboli di reindirizzamento.

Ho scritto uno script abbastanza semplice per testare questo:

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

Eseguo questo script in questo modo:

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

Presumibilmente, verranno indentate solo le righe stampate su STDERR. Tuttavia, in realtà non funziona in questo modo, come vedo:

    Normal Text.
    Error Text. 

Cosa sto facendo di sbagliato qui?

Risposte:


26

Non so quale testo usi il tuo libro, ma il manuale di bash è chiaro (se hai già un po 'di familiarità con i reindirizzamenti):

Se |&viene utilizzato, l'errore standard di command1, oltre alla sua uscita standard, è collegato all'ingresso standard di command2 attraverso la pipe; è una scorciatoia per 2>&1 |. Questo reindirizzamento implicito dell'errore standard sull'output standard viene eseguito dopo qualsiasi reindirizzamento specificato dal comando.

Pertanto, se non si desidera combinare l'output standard e l'errore standard, è necessario reindirizzare l'output standard da qualche altra parte. Vedi Come grep flusso di errori standard (stderr)?

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

Sia fd 1 che 3 di script.she sedpunteranno comunque alla destinazione stdout originale. Se vuoi essere un buon cittadino, puoi chiudere quelle fd 3 di cui quei comandi non hanno bisogno:

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

bashe ksh93può condensare il >&3 3>&-to >&3-(fd move).


Il manuale di Bash non è del tutto chiaro per me. Io non capisco il motivo per cui si dovrebbe occupare come ./script.sh > /tmp/stdout_goes_here |& grep 'grepping_script_stderr'non funziona come previsto, vale a dire: redirect script.sh's stdout(che, secondo il frammento di manuale dovrebbe accadere prima), quindi lasciare grepper elaborare la sceneggiatura di stderr. Invece, stderre tdout` finiscono entrambi instdout_goes_here
sxc731 l'

1
@ sxc731 |&è shorthard per 2>&1 |. Quindi >/tmp/stdout_goes_here |&reindirizza stdout a /tmp/stdout_goes_here, quindi 2>&1reindirizza stderr ovunque stdout stia andando, che è /tmp/stdout_goes_here, e infine |non riceve alcun input perché l'output del comando è stato reindirizzato. Tieni presente che i >&1reindirizzamenti a dove sta andando il descrittore di file 1 , non a dove finirà il descrittore di file 1 . Per reindirizzare solo stderr e reindirizzare stdout su un file, un modo è 2>&1 >/tmp/stdout_goes_here |.
Gilles 'SO- smetti di essere malvagio' l'

6

|&pipe da stderr a stdin, come 2>&1 |, quindi il prossimo programma otterrà entrambi su stdin.

$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.

Oh, quindi è sostanzialmente equivalente all'espressione più lunga runcommand 2>&1 | tee? cioè runcommand |& tee?
Naftuli Kay,

si, sono uguali.
Kevin,

1

|&in bash è solo una scorciatoia (non terribilmente portatile) 2>&1 |, quindi dovresti vedere ogni riga rientrata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.