Domanda

In una shell Unix, se voglio combinare stderr e stdout nel flusso stdout per ulteriore manipolazione, posso aggiungere quanto segue alla fine del mio comando:

2>&1

Quindi, se voglio usare head sull'output di g ++ , posso fare qualcosa del genere:

g++ lots_of_errors 2>&1 | head

così posso vedere solo i primi pochi errori.

Ho sempre difficoltà a ricordare questo, e devo costantemente andare a cercarlo, ed è principalmente perché non capisco completamente la sintassi di questo particolare trucco.

Qualcuno può scomporlo e spiegare carattere per carattere cosa significa 2 > & amp; 1 ?

È stato utile?

Soluzione

Il descrittore di file 1 è l'output standard ( stdout ).
Il descrittore di file 2 è l'errore standard ( stderr ).

Ecco un modo per ricordare questo costrutto (anche se non è del tutto esatto): all'inizio, 2 > 1 può sembrare un buon modo per reindirizzare stderr a stdout . Tuttavia, verrà in realtà interpretato come "reindirizzare stderr su un file chiamato 1 " ;. & amp; indica che ciò che segue è un descrittore di file e non un nome di file. Quindi il costrutto diventa: 2 > & amp; 1 .

Altri suggerimenti

echo test > afile.txt

reindirizza stdout su afile.txt . È lo stesso che fare

echo test 1> afile.txt

Per reindirizzare stderr, devi:

echo test 2> afile.txt

> & amp; è la sintassi per reindirizzare uno stream a un altro descrittore di file: 0 è stdin, 1 è stdout e 2 è stderr.

Puoi reindirizzare stdout a stderr facendo:

echo test 1>&2 # or echo test >&2

O viceversa:

echo test 2>&1

Quindi, in breve ... 2 > reindirizza stderr a un file (non specificato), aggiungendo & amp; 1 reindirizza stderr a stdout.

Alcuni trucchi per il reindirizzamento

Alcune particolarità della sintassi al riguardo possono avere comportamenti importanti. Ci sono alcuni piccoli esempi di reindirizzamenti, STDERR , STDOUT e argomenti ordinamento .

1 - Sovrascrivere o aggiungere?

Simbolo > significa reindirizzamento .

  • > significa invia a tutto il file completato , sovrascrivendo la destinazione se esiste (vedi la funzione bash noclobber su # 3 più tardi).
  • > > significa che invia in aggiunta a si aggiungerebbe al target se esiste.

In ogni caso, il file verrebbe creato se non esistesse.

2 - La riga di comando della shell dipende dall'ordine !!

Per provare questo, abbiamo bisogno di un semplice comando che invierà qualcosa su entrambi gli output :

$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan  7 11:49 /tmp

(Mi aspettavo di non avere una directory chiamata / tnt , ovviamente;). Bene, ce l'abbiamo !!

Quindi, vediamo:

$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1

$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory

L'ultima riga di comando scarica STDERR sulla console e sembra non essere il comportamento previsto ... Ma ...

Se vuoi creare un post filtro su un output, l'altro o entrambi:

$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan  7 12:02 /tmp --->

$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory

$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'

$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->

Nota che l'ultima riga di comando in questo paragrafo è esattamente la stessa del paragrafo precedente, in cui ho scritto sembra non essere il comportamento previsto (quindi, questo potrebbe anche essere un comportamento previsto).

Bene, ci sono alcuni trucchi sui reindirizzamenti, per eseguendo operazioni diverse su entrambi gli output :

$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2  2>&1  | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan  7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory

Nota: il descrittore & amp; 9 si presenta spontaneamente a causa di ) 9 > & amp; 2 .

Addendum: nota! Con la nuova versione di ( > 4.0 ) c'è una nuova funzione e una sintassi più sexy per fare questo tipo di cose:

$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory

E infine per una formattazione dell'output a cascata simile:

$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
     1  O: drwxrwxrwt 118 root root 196608 Jan  7 12:29 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Addendum: nota! Stessa nuova sintassi, in entrambi i modi:

$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
     1  O: drwxrwxrwt 17 root root 28672 Nov  5 23:00 /tmp
     2  E: ls: cannot access /tnt: No such file or directory

Dove STDOUT passa attraverso un filtro specifico, STDERR su un altro e infine entrambi gli output uniti passano attraverso un terzo filtro di comando.

3 - Una parola sull'opzione noclobber e sulla sintassi > |

Si tratta di sovrascrittura :

Mentre set -o noclobber indica a bash di non sovrascrivere qualsiasi file esistente, la sintassi > | ti consente di superare questa limitazione:

$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:15 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:19 CET 2013

$ date > $testfile ; cat $testfile
Mon Jan  7 13:18:21 CET 2013

Il file viene sovrascritto ogni volta, bene ora:

$ set -o noclobber

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan  7 13:18:21 CET 2013

Passa attraverso > | :

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

Disattivando questa opzione e / o chiedendo se è già impostato.

$ set -o | grep noclobber
noclobber           on

$ set +o noclobber

$ set -o | grep noclobber
noclobber           off

$ date > $testfile ; cat $testfile
Mon Jan  7 13:24:27 CET 2013

$ rm $testfile

4 - Ultimo trucco e altro ...

Per reindirizzare entrambi l'output da un determinato comando, vediamo che una sintassi corretta potrebbe essere:

$ ls -ld /tmp /tnt >/dev/null 2>&1

per questo caso speciale , esiste una sintassi di scelta rapida: & amp; > ... o > & amp;

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

Nota: se 2>&1 esiste, 1>&2 è una sintassi corretta anche:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b- Ora, ti lascio pensare a:

$ ls -ld /tmp /tnt 2>&1 1>&2  | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

$ ls -ld /tmp /tnt 1>&2 2>&1  | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb  9 11:08 /tmp/

4c- Se sei interessato a più informazioni

Puoi leggere il bel manuale premendo:

man -Len -Pless\ +/^REDIRECTION bash

in una console; -)

Ho trovato questo brillante post sul reindirizzamento: Tutto sui reindirizzamenti

Reindirizza sia l'output standard che l'errore standard su un file

  

$ command & amp; > file

Questo one-liner utilizza l'operatore & amp; > per reindirizzare entrambi i flussi di output - stdout e stderr - dal comando al file. Questa è la scorciatoia di Bash per reindirizzare rapidamente entrambi i flussi alla stessa destinazione.

Ecco come appare la tabella dei descrittori di file dopo che Bash ha reindirizzato entrambi i flussi:

 Inserisci qui la descrizione dell'immagine

Come puoi vedere, sia stdout che stderr ora puntano a file . Quindi qualsiasi cosa scritta su stdout e stderr viene scritta nel file .

Esistono diversi modi per reindirizzare entrambi i flussi sulla stessa destinazione. Puoi reindirizzare ciascuno stream uno dopo l'altro:

  

$ command > file 2 > & amp; 1

Questo è un modo molto più comune per reindirizzare entrambi i flussi su un file. Il primo stdout viene reindirizzato al file, quindi lo stderr viene duplicato per essere uguale allo stdout. Quindi entrambi i flussi finiscono per puntare a file .

Quando Bash vede diversi reindirizzamenti, li elabora da sinistra a destra. Esaminiamo i passaggi e vediamo come succede. Prima di eseguire qualsiasi comando, la tabella dei descrittori di file di Bash è simile alla seguente:

 Inserisci qui la descrizione dell'immagine

Ora Bash elabora il primo file > di reindirizzamento. L'abbiamo visto prima e fa riferimento allo stdout al file:

 Inserisci qui la descrizione dell'immagine

Next Bash vede il secondo reindirizzamento 2 > & amp; 1. Non abbiamo mai visto questo reindirizzamento prima. Questo duplica il descrittore di file 2 per essere una copia del descrittore di file 1 e otteniamo:

 Inserisci qui la descrizione dell'immagine

Entrambi i flussi sono stati reindirizzati al file.

Comunque fai attenzione qui! Scrivendo

  

comando > file 2 > & amp; 1

non è lo stesso della scrittura:

  

$ comando 2 > & amp; 1 > file

L'ordine dei reindirizzamenti conta in Bash! Questo comando reindirizza solo l'output standard al file. Lo stderr continuerà a stampare sul terminale. Per capire perché ciò accada, eseguiamo di nuovo i passaggi. Quindi, prima di eseguire il comando, la tabella dei descrittori di file è simile alla seguente:

 Inserisci qui la descrizione dell'immagine

Ora Bash elabora i reindirizzamenti da sinistra a destra. Per prima cosa vede 2 > & amp; 1 quindi duplica stderr in stdout. La tabella dei descrittori di file diventa:

 Inserisci qui la descrizione dell'immagine

Ora Bash vede il secondo reindirizzamento, > file , e reindirizza stdout su file:

 Inserisci qui la descrizione dell'immagine

Vedi cosa succede qui? Stdout ora punta al file, ma lo stderr punta ancora al terminale! Tutto ciò che viene scritto su stderr viene ancora stampato sullo schermo! Quindi stai molto, molto attento con l'ordine dei reindirizzamenti!

Nota anche che in Bash, scrivendo

  

$ command & amp; > file

è esattamente lo stesso di:

  

$ command > & amp; file

I numeri si riferiscono ai descrittori di file (fd).

  • Zero è stdin
  • Uno è stdout
  • Due è stderr

2 > & amp; 1 reindirizza fd 2 a 1.

Funziona con qualsiasi numero di descrittori di file se il programma li utilizza.

Puoi guardare /usr/include/unistd.h se li dimentichi:

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

Detto questo, ho scritto strumenti C che usano descrittori di file non standard per la registrazione personalizzata in modo da non vederlo a meno che non lo reindirizzi a un file o qualcosa del genere.

Questo costrutto invia il flusso di errori standard ( stderr ) alla posizione corrente dell'output standard ( stdout ) - questo problema con la valuta sembra sono state trascurate dalle altre risposte.

Puoi reindirizzare qualsiasi handle di output verso un altro utilizzando questo metodo, ma viene spesso utilizzato per canalizzare gli stream stdout e stderr in un singolo flusso per l'elaborazione.

Alcuni esempi sono:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

Nota che l'ultimo non dirigerà stderr su outfile2 - lo reindirizza a ciò che stdout era quando è stato riscontrato l'argomento ( outfile1 ) e quindi reindirizza stdout su outfile2 .

Ciò consente alcuni stratagemmi piuttosto sofisticati.

2 > & amp; 1 è un costrutto shell POSIX. Ecco una ripartizione, token per token:


2 : " Errore standard " descrittore del file di output.

> & amp; : Duplica un descrittore di file di output (una variante di Reindirizzamento output operatore > ). Dato [x] > & amp; [y] , il descrittore di file indicato con x viene creato come una copia del descrittore di file di output y .

1 " Output standard " descrittore del file di output.

L'espressione 2 > & amp; 1 copia il descrittore di file 1 nella posizione 2 , quindi qualsiasi output scritto in 2 (" errore standard ") nell'ambiente di esecuzione passa allo stesso file originariamente descritto da 1 (" output standard ").


Ulteriore spiegazione:

Descrittore di file : " Un numero intero univoco e non negativo per processo utilizzato per identificare un file aperto a scopo di accesso al file. "

Output / errore standard : fare riferimento alla nota seguente nella Reindirizzamento sezione della documentazione della shell:

  

I file aperti sono rappresentati da numeri decimali che iniziano con zero. Il valore più grande possibile è definito dall'implementazione; tuttavia, tutte le implementazioni devono supportare almeno da 0 a 9, incluso, per l'uso da parte dell'applicazione. Questi numeri sono chiamati "descrittori di file". I valori 0, 1 e 2 hanno un significato speciale e usi convenzionali e sono implicati da alcune operazioni di reindirizzamento; sono indicati rispettivamente come input standard, output standard ed errore standard. I programmi solitamente prendono l'input dall'input standard e scrivono l'output sull'output standard. I messaggi di errore sono generalmente scritti su errori standard. Gli operatori di reindirizzamento possono essere preceduti da una o più cifre (senza caratteri intermedi consentiti) per designare il numero del descrittore di file.

2 è l'errore standard della console.

1 è l'output standard della console.

Questo è lo standard Unix e Windows segue anche POSIX.

es. quando corri

perl test.pl 2>&1

l'errore standard viene reindirizzato all'output standard, quindi è possibile visualizzare entrambi gli output insieme:

perl test.pl > debug.log 2>&1

Dopo l'esecuzione, puoi vedere tutto l'output, inclusi gli errori, in debug.log.

perl test.pl 1>out.log 2>err.log

Quindi l'output standard passa a out.log e l'errore standard a err.log.

Ti consiglio di provare a capirli.

Per rispondere alla tua domanda: prende qualsiasi output di errore (normalmente inviato a stderr) e lo scrive nell'output standard (stdout).

Ciò è utile, ad esempio "altro" quando è necessario il paging per tutto l'output. Alcuni programmi come stampare le informazioni sull'utilizzo in stderr.

Per aiutarti a ricordare

  • 1 = output standard (dove i programmi stampano output normale)
  • 2 = errore standard (dove i programmi stampano errori)

" 2 > & amp; 1 " indica semplicemente tutto ciò che è stato inviato a stderr, invece a stdout.

Consiglio anche di leggere questo post sul reindirizzamento degli errori dove questo l'argomento è trattato in dettaglio.

Dal punto di vista di un programmatore, significa esattamente questo:

dup2(1, 2);

Vedi la pagina man .

Comprendere che 2 > & amp; 1 è una copia spiega anche perché ...

command >file 2>&1

... non è lo stesso di ...

command 2>&1 >file

Il primo invierà entrambi i flussi in file , mentre il secondo invierà errori in stdout e l'output ordinario in file .

Persone, ricorda sempre il suggerimento di paxdiablo sulla attuale posizione del target di reindirizzamento ... è importante.

Il mio mnemonico personale per l'operatore 2 > & amp; 1 è questo:

  • Pensa a & amp; come 'e' o 'add' (il personaggio è un ampers - e , vero?)
  • Quindi diventa: 'reindirizza 2 (stderr) su dove 1 (stdout) è già / attualmente è e aggiungi entrambi flussi .

Lo stesso mnemonico funziona anche per l'altro reindirizzamento usato di frequente, 1 > & amp; 2 :

  • Pensa a & amp; che significa e o aggiungi ... (hai l'idea della e commerciale, sì?)
  • Quindi diventa: 'reindirizza 1 (stdout) su dove 2 (stderr) è già / attualmente è e aggiungi entrambi flussi .

E ricorda sempre: devi leggere le catene di reindirizzamenti "dalla fine", da destra a sinistra ( non da sinistra a destra).

A condizione che / foo non esista sul tuo sistema e / tmp non ...

$ ls -l /tmp /foo

stamperà il contenuto di / tmp e stamperà un messaggio di errore per /foo

$ ls -l /tmp /foo > /dev/null

invierà il contenuto di / tmp a / dev / null e stamperà un messaggio di errore per /foo

$ ls -l /tmp /foo 1> /dev/null

farà esattamente lo stesso (notare 1 )

$ ls -l /tmp /foo 2> /dev/null

stamperà il contenuto di / tmp e invierà il messaggio di errore a /dev/null

$ ls -l /tmp /foo 1> /dev/null 2> /dev/null

invierà sia l'elenco che il messaggio di errore a /dev/null

$ ls -l /tmp /foo > /dev/null 2> &1

è una scorciatoia

È come passare l'errore allo stdout o al terminale.

Cioè, cmd non è un comando:

$cmd 2>filename
cat filename

command not found

L'errore viene inviato al file in questo modo:

2>&1

L'errore standard viene inviato al terminale.

  

Reindirizzamento input

     

Il reindirizzamento dell'input causa il file il cui nome   risulta dall'espansione della parola da aprire per la lettura in archivio   descrittore n o input standard (descrittore di file 0) se n lo è   non specificato.

     

Il formato generale per il reindirizzamento dell'input è:

[n]<word
     

Reindirizzamento dell'output

     

Il reindirizzamento dell'output provoca il file di cui   il nome deriva dall'espansione della parola da aprire per la scrittura   descrittore di file n, oppure lo standard output (descrittore di file 1) se n   non è specificato. Se il file non esiste, viene creato; se è così   esiste, viene troncato a dimensione zero.

     

Il formato generale per il reindirizzamento dell'output è:

[n]>word
     

Spostamento dei descrittori di file

     

L'operatore di reindirizzamento,

[n]<&digit-
     

sposta la cifra del descrittore di file nel descrittore di file n o in   input standard (descrittore di file 0) se n non è specificato.   la cifra viene chiusa dopo essere stata duplicata in n.

     

Allo stesso modo, l'operatore di reindirizzamento

[n]>&digit-
     

sposta la cifra del descrittore di file nel descrittore di file n o in   output standard (descrittore di file 1) se n non è specificato.

Rif:

man bash

Digita / ^ REDIRECT per individuare la sezione redirection , e scopri di più ...

Una versione online è qui: 3.6 Reindirizzamenti

PS:

Molte volte, man era il potente strumento per imparare Linux.

0 per input, 1 per stdout e 2 per stderr.

Un suggerimento : somecmd > 1.txt 2 > & amp; 1 è corretto, mentre somecmd 2 > & amp; 1 > 1.txt è totalmente sbagliato senza alcun effetto!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top