Domanda Nella shell, cosa significa "2> & 1"?


In una shell Unix, se voglio unire stderr e stdout dentro stdout stream per ulteriori manipolazioni, posso aggiungere quanto segue alla fine del mio comando:

2>&1

Quindi, se voglio usare head sull'output da 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 personaggio per carattere cosa 2>&1  si intende?


1733
2018-05-03 22:57


origine


risposte:


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

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


1942
2018-05-03 23:04



echo test > afile.txt

reindirizza stdout a afile.txt. Questo è lo stesso di fare

echo test 1> afile.txt

Per reindirizzare lo stderr, devi:

echo test 2> afile.txt

>& è la sintassi per reindirizzare un flusso verso un altro descrittore di file: 0 è stdin, 1 è stdout e 2 è stderr.

È possibile reindirizzare lo stdout su stderr eseguendo:

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

O vice versa:

echo test 2>&1

Quindi, in breve ... 2> reindirizza lo stderr in un file (non specificato), aggiungendolo &1 reindirizza lo stderr allo stdout.


481
2018-05-03 22:59



Alcuni trucchi sul reindirizzamento

Alcune particolarità della sintassi su questo possono avere comportamenti importanti. Ci sono alcuni piccoli esempi di reindirizzamenti, STDERR, STDOUTe argomenti ordinazione.

1 - Sovrascrittura o aggiunta?

Simbolo > significare reindirizzamento.

  • > significare inviare a tutto il file completato, sovrascrivere il target se esiste (vedi noclobber caratteristica bash a # 3 dopo).
  • >> significare inviare in aggiunta a aggiungerebbe all'obiettivo se esiste.

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

2 - The riga di comando della shell è dipendente dall'ordine !!

Per testare questo, abbiamo bisogno un semplice comando che invierà qualcosa su entrambe le uscite:

$ 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 di nome /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

Gli ultimi dump della riga di comando STDERR alla console, e sembra non essere il comportamento previsto ... Ma ...

Se vuoi fare un po ' post filtraggio circa un'uscita, l'altra o entrambe:

$ 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 sembra non essere il comportamento previsto (quindi, questo potrebbe anche essere un comportamento previsto).

Bene, ci sono alcuni trucchi sui reindirizzamenti, per facendo 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: &9descrittore si sarebbe verificato spontaneamente a causa di ) 9>&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:

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

3 - Una parola su noclobber opzione e >| sintassi

Questo è circa sovrascrivendo:

Mentre set -o noclobber istruire bash a non sovrascrivere qualsiasi file esistente, il >| 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 il reindirizzamento entrambi uscita da un dato comando, vediamo che una sintassi corretta potrebbe essere:

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

per questo speciale caso, c'è una sintassi di scelta rapida: &> ... o >&

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

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

Nota: se 2>&1 esistere, 1>&2 è anche 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 ti interessa Di Più informazione

Puoi leggere il bel manuale colpendo:

man -Len -Pless\ +/^REDIRECTION bash

in un  console ;-)


256
2018-04-29 16:33



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

  • Zero è stdin 
  • Uno è stdout 
  • Due è 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.


67
2018-05-03 22:58



Questo costrutto invia lo stream standard di errore (stderr) al attuale posizione dell'output standard (stdout) - questo problema valutario sembra essere stato trascurato dalle altre risposte.

È possibile reindirizzare qualsiasi handle di output a un altro utilizzando questo metodo, ma è più spesso utilizzato per il canale stdout e stderr flussi 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 lo farà non diretto stderr a outfile2 - lo reindirizza a cosa stdout è stato quando l'argomento è stato incontrato (outfile1) e poi redirect stdout a outfile2.

Ciò consente alcuni trucchi piuttosto sofisticati.


49
2018-05-03 23:54



Ho trovato questo brillante post sul reindirizzamento: Tutto su reindirizzamenti

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

$ comando &> file

Questo one-liner usa il &> 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:

Enter image description here

Come puoi vedere, sia lo stdout che lo stderr ora puntano file. Quindi qualsiasi cosa scritta su stdout e stderr viene scritta 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 a 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:

Enter image description here

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

Enter image description here

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:

Enter image description here

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:

Enter image description here

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:

Enter image description here

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

Enter image description here

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


46
2017-10-29 13:04



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


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

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

1 "Uscita standard"descrittore del file di output.

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


Ulteriori spiegazioni:

File Descriptor: "Un intero univoco, non negativo per processo utilizzato per identificare un file aperto ai fini dell'accesso ai file."

Uscita / errore standard: Fare riferimento alla seguente nota in reindirizzamento sezione 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.


13
2017-12-25 06:43



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 sul reindirizzamento degli errori dove questo argomento è trattato in dettaglio.


12
2018-05-03 23:24



2 è l'errore standard della console.

1 è lo standard output della console.

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

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


12
2017-07-19 03:23