Perché '>' non reindirizza i messaggi di errore da gcc?


9

Ho memorizzato il seguente programma in new.c

int main() 
{ 
    a;
    return 0; 
}

Restituisce un messaggio di errore. Voglio inviare questo messaggio a un file. Quindi ho usato il seguente comando

gcc new.c > temp.txt

Ma stavo ancora ottenendo l'output sul terminale. Sto usando Ubuntu 13.04. Come posso farlo funzionare?


Risposte:


16

Quando si compila un programma con gcc, ci sono diversi tipi di output: to stdoute stderr. Normalmente, il flusso >diretto stdouta un file (ad esempio, printf("hello world\n");viene inviato il risultato di a stdout). Tuttavia, stderrcontinua a essere inviato allo schermo, dal momento che si presume che sia "qualcosa di eccezionale di cui devi essere informato".

C'è un modo per reindirizzare stderr a un file: lo fai con il seguente comando (non molto intuitivo):

gcc new.c &> myFile

dove si &>trova "abbreviazione bash" per "reindirizzare tutto". Come sottolineato da @CharlesDuffy, il modulo conforme a POSIX è

gcc new.c > myFile 2>&1

Questo significa "compila 'new.c' e invia stdouta myFile. E invia stderr(2) nello stesso posto di stdout( &1=" lo stesso posto di stdout ").

Ulteriori dettagli sui diversi reindirizzamenti sono disponibili su http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html e http://mywiki.wooledge.org/BashFAQ/055

A proposito, se vuoi inviare qualcosa all'interno del tuo programma in modo specifico stderr, puoi farlo con quanto segue

fprintf(stderr, "hello world - this is urgent.\n");

Se lo includi in un programma, esegui il programma e invia l'output "normale" a un file, questo verrà comunque visualizzato sulla console. Quindi, se si compila quanto sopra nell'eseguibile urgent, quindi digitare

./urgent > /dev/null

sulla console, l'output verrà visualizzato sullo schermo.


2
mywiki.wooledge.org/BashFAQ/055 è probabilmente una migliore introduzione al reindirizzamento. Inoltre, si dovrebbe davvero introdurre il form ( >myFile 2>&1) conforme a POSIX e l'estensione bash ( &>).
Charles Duffy,

@CharlesDuffy - entrambi i punti molto buoni. Li includerò nella mia risposta per completezza.
Floris,

11

Poiché i >reindirizzamenti solo stdout e gli errori vengono scritti stderr, è necessario utilizzare uno dei seguenti:

gcc new.c &> temp.txt ## redirect both stdout and stderr using bash or zsh only

...o...

gcc new.c >temp.txt 2>&1 ## redirect both stdout and stderr in any POSIX shell

&>è un'estensione BASH che reindirizza sia stdoute stderrin un file; in caso contrario, l'approccio più semplice è quello di prima stdout redirect ( >temp.txt), e poi fare stderr (FD 2) una copia del handle di file già reindirizzato su stdout (FD 1), in questo modo: 2>&1.


4

Come hanno detto gli altri, Linux fornisce due diversi flussi di output:

stdout , o "output standard" è dove va tutto l'output normale.
              Puoi fare riferimento usando il descrittore di file 1.

stderr , o "errore standard" è un flusso separato per informazioni fuori banda.
              Puoi fare riferimento usando il descrittore di file 2.

Perché due diversi flussi di output? Considera una pipeline di comandi immaginari:

 decrypt $MY_FILE | grep "secret" | sort > secrets.txt

Ora immagina che il decryptcomando fallisca e generi un messaggio di errore. Se avesse inviato quel messaggio a stdout, lo avrebbe spedito nel tubo, e se non avesse la parola "segreto" non lo vedresti mai. Quindi finiresti con un file di output vuoto, senza idea di cosa sia andato storto.

Tuttavia, poiché la pipe acquisisce solo stdout, il decryptcomando può inviare i suoi errori a stderr, dove verranno visualizzati sulla console.

Puoi reindirizzare stdoute stderr, insieme o indipendentemente:

# Send errors to "errors.txt" and output to "secrets.txt"
# The following two lines are equivalent, as ">" means "1>"
decrypt $MY_FILE 2> errors.txt > secrets.txt
decrypt $MY_FILE 2> errors.txt 1> secrets.txt

È possibile reindirizzare gli errori stdouted elaborarli come se fossero output normali:

# The operation "2>&1" means "redirect file descriptor 2 to file
# descriptor 1. So this sends all output from stderr to stdout.
# Note that the order of redirection is important.
decrypt $MY_FILE > errors.txt 2>&1 

# This may be confusing.  It will store the normal output in a file
# and send error messages to stdout, where they'll be captured by 
# the pipe and then sorted.
decrypt $MY_FILE 2>&1 > output.txt | sort

Puoi anche usare una notazione "abbreviata" per reindirizzare sia stdout che stderr allo stesso file:

decrypt $MY_FILE &> output.txt

E, infine, l' >operatore troncerà prima il suo file di output prima di scriverlo. Se, invece, desideri aggiungere dati a un file esistente, usa l' >>operatore:

decrypt $MY_FILE 2>> more_errors.txt >> more_secrets.txt
decrypt $MY_FILE >> more_output.txt 2>&1

1
Due cavilli: (1) L'uso di espansioni di parametri non quotate ( $FOO) è una fonte comune di bug, e dimostrarlo negli esempi non è così eccezionale. (2) L'uso di nomi di variabili in maiuscolo è il motivo principale dei conflitti tra namespace e variabili incorporate (maiuscole per convenzione) e variabili locali (minuscole per convenzione). (3) Incoraggiare le persone a utilizzare ripetutamente >>(che riapre il file ogni volta che viene utilizzato in un comando) anziché aprire un file una volta e lasciare il descrittore di file aperto per l'uso da parte di più comandi si traduce in codice inefficiente.
Charles Duffy,

... sull'ultimo punto, confronta con: exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Charles Duffy il

+1 Grazie per avermi reso onesto, @CharlesDuffy. Tutti i punti positivi. Ho omesso intenzionalmente la execsemplicità, sebbene in pratica sia generalmente una strategia migliore.

Inoltre, può essere compresso in o (dove devono esserci spazi prima e dopo il e un prima del ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man dice "Ripristina Monica" il
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.