bash - redirezione - script 2>& 1




Nella shell, cosa significa "2> & 1"? (10)

In una shell Unix, se voglio combinare stderr e stdout nel flusso stdout per ulteriori manipolazioni, 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

quindi posso vedere solo i primi errori.

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

Qualcuno può rompere questo e spiegare carattere per carattere cosa significa 2>&1 ?


Reindirizzamento dell'input

Il reindirizzamento dell'ingresso fa sì che il file il cui nome risulta dall'espansione della parola da aprire per la lettura sul descrittore di file n, o dallo standard input (descrittore di file 0) se n non è specificato.

Il formato generale per reindirizzare l'input è:

[n]<word

Reindirizzamento dell'output

Il reindirizzamento dell'output provoca il file il cui nome risulta dall'espansione della parola da aprire per la scrittura sul descrittore di file n, o dallo standard output (descrittore di file 1) se n non è specificato. Se il file non esiste viene creato; se esiste, viene troncato a zero dimensioni.

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 lo standard input (descrittore di file 0) se n non è specificato. la cifra viene chiusa dopo essere stata duplicata su n.

Allo stesso modo, l'operatore di reindirizzamento

[n]>&digit-

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

Rif:

man bash

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

Una versione online è qui: 3.6 Reindirizzamenti

PS:

Un sacco di tempo, l' man era il potente strumento per imparare Linux.


Alcuni trucchi sul reindirizzamento

Alcune particolarità della sintassi su questo possono avere comportamenti importanti. Vi sono alcuni piccoli esempi di reindirizzamenti, STDERR , STDOUT e ordinamento di argomenti.

1 - Sovrascrittura o aggiunta?

Simbolo > media reindirizzamento .

  • > significa mandare a tutto il file completato , sovrascrivendo il target se esiste (si veda la funzione noclobber bash al n.3 più tardi).
  • >> significa inviare oltre a aggiungere all'obiettivo se esiste.

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

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

Per testare 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 aspetto che tu non abbia 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 nella console e sembra che non sia il comportamento previsto ... Ma ...

Se vuoi fare un po 'di post filtraggio 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 --->

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

Bene, ci sono alcuni trucchi sui reindirizzamenti, per fare diverse operazioni su entrambe le uscite :

$ ( 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: &9 descrittore si verificherebbe spontaneamente a causa di ) 9>&2 .

Addendum: nota! Con la nuova versione di bash ( >4.0 ) c'è una nuova funzionalità 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:

$ ((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 a un altro e infine entrambe le uscite unite passano attraverso un terzo filtro di comando.

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

Riguarda la sovrascrittura :

Mentre set -o noclobber ordina a bash di non sovrascrivere alcun 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 con >| :

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

$ 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 sia l' output da un dato 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: &> ... o >&

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

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

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

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

4b- Ora, ti farò pensare:

$ 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 maggiori informazioni

Puoi leggere il bel manuale colpendo:

man -Len -Pless\ +/^REDIRECTION bash

in una console bash ;-)


2 è l'errore standard della console.

1 è lo standard output della console.

Questo è lo standard Unix e Windows segue anche il POSIX.

Ad esempio quando corri

perl test.pl 2>&1

l'errore standard viene reindirizzato all'output standard, quindi puoi vedere entrambe le uscite insieme:

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

Dopo l'esecuzione, è possibile vedere tutti gli output, inclusi gli errori, nel debug.log.

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

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

Ti suggerisco di provare a capirli.


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

$ 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 (nota 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 stenografia


Ho trovato questo brillante post sul reindirizzamento: Tutto sui reindirizzamenti

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

$ comando &> file

Questo one-liner utilizza l'operatore &> per reindirizzare entrambi i flussi di output, stdout e stderr, da un comando all'altro. Questa è la scorciatoia di Bash per reindirizzare rapidamente entrambi i flussi verso la stessa destinazione.

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

Come puoi vedere, sia stdout che stderr ora puntano al 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 ogni stream uno dopo l'altro:

$ comando> file 2> & 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 a stdout. Quindi entrambi i flussi finiscono per puntare al file .

Quando Bash vede diversi reindirizzamenti li elabora da sinistra a destra. Esaminiamo i passaggi e vediamo come ciò accade. Prima di eseguire qualsiasi comando, la tabella del descrittore di file di Bash ha il seguente aspetto:

Ora Bash elabora il primo file di reindirizzamento. Abbiamo già visto questo e rende il file stdout point:

Avanti Bash vede il secondo reindirizzamento 2> & 1. Non abbiamo visto questo reindirizzamento prima. Questo duplica il descrittore di file 2 in modo che sia una copia del descrittore di file 1 e otteniamo:

Entrambi i flussi sono stati reindirizzati al file.

Comunque fai attenzione qui! scrittura

comando> file 2> & 1

non è lo stesso della scrittura:

$ comando 2> & 1> file

L'ordine di reindirizzare le cose in Bash! Questo comando reindirizza solo lo standard output al file. Lo stderr continuerà a stampare sul terminale. Per capire perché ciò accade, riprendiamo i passaggi. Quindi, prima di eseguire il comando, la tabella del descrittore di file ha il seguente aspetto:

Ora Bash elabora i reindirizzamenti da sinistra a destra. Prima vede 2> & 1 quindi duplica lo stderr allo stdout. La tabella del descrittore di file diventa:

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

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

Si noti inoltre che in Bash, la scrittura

$ comando &> file

è esattamente la stessa di:

$ comando> & file


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

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

2>&1 reindirizza da 2 a 1 fd.

Questo funziona per qualsiasi numero di descrittori di file se il programma li usa.

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 utilizzano descrittori di file non standard per la registrazione personalizzata, in modo che non vengano visualizzati a meno che non lo si reindirizzi a un file o qualcosa del genere.


Le persone, ricordate sempre l 'indizio di paxdiablo sulla posizione attuale del target di reindirizzamento ... È importante.

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

  • Pensa a & come significato 'and' o 'add' (il personaggio è un ampers - e , non è vero?)
  • Così diventa: 'reindirizza 2 (stderr) in cui 1 (stdout) è già / attualmente è e aggiungi entrambi i flussi' .

Lo stesso lavoro mnemonico per l'altro reindirizzamento di uso frequente, 1>&2 :

  • Pensa and intendi and add ... (hai un'idea della e commerciale, sì?)
  • Così diventa: 'reindirizza 1 (stdout) in cui 2 (stderr) è già / attualmente è e aggiungi entrambi i flussi' .

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


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

Ciò è utile con, per esempio, "altro" quando è necessario il paging per tutti gli output. Alcuni programmi come stampare 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> & 1" punta semplicemente a tutto ciò che è stato inviato a stderr, invece allo stdout.

Raccomando anche di leggere questo post sull'errore che reindirizza dove questo argomento è trattato in dettaglio.


Questo costrutto invia il flusso di errore standard ( stderr ) alla posizione corrente dell'output standard ( stdout ) - questo problema di valuta sembra essere stato trascurato dalle altre risposte.

È possibile reindirizzare qualsiasi handle di output a un altro utilizzando questo metodo, ma viene spesso utilizzato per il stdout stderr e stderr in un singolo stream 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 indirizzerà stderr a outfile2 - lo reindirizza a quale stdout era quando l'argomento è stato incontrato ( outfile1 ) e poi reindirizza da stdout a outfile2 .

Ciò consente alcuni trucchi piuttosto sofisticati.


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

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

>& : Duplica un operatore descrittore del file di output (una variante dell'operatore di reindirizzamento dell'output > ). Dato [x]>&[y] , il descrittore di file denotato da x è fatto per essere una copia del descrittore del file di output y .

1 descrittore del file di output " Standard output ".

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

Ulteriori spiegazioni:

Descrittore di file : "Un numero intero non negativo unico per processo utilizzato per identificare un file aperto ai fini dell'accesso ai file."

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

I file aperti sono rappresentati da numeri decimali che iniziano con zero. Il più grande valore possibile è definito dall'implementazione; tuttavia, tutte le implementazioni devono supportare almeno da 0 a 9, compreso, per l'utilizzo 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 certe operazioni di reindirizzamento; sono indicati come input standard, output standard e errore standard, rispettivamente. I programmi di solito prendono il loro input dall'input standard e scrivono l'output sullo standard output. I messaggi di errore sono generalmente scritti su errore 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.





redirect