Pourquoi «>» ne redirige-t-il pas les messages d'erreur de gcc?

9

J'ai stocké le programme suivant dans new.c

int main() 
{ 
    a;
    return 0; 
}

Il renvoie un message d'erreur. Je veux envoyer ce message dans un fichier. J'ai donc utilisé la commande suivante

gcc new.c > temp.txt

Mais je recevais toujours la sortie sur le terminal. J'utilise Ubuntu 13.04. Comment puis-je le faire fonctionner?

Alex
la source
Pour référence, voir aussi Quels sont les opérateurs de contrôle et de redirection du shell?
G-Man dit 'Reinstate Monica' le

Réponses:

16

Lorsque vous compilez un programme avec gcc, il existe différents types de sortie: vers stdoutet stderr. Normalement, le flux >sera dirigé stdoutvers un fichier (par exemple, le résultat d'un printf("hello world\n");est envoyé à stdout). Cependant, le stderrcontinue d'être envoyé à l'écran, car il est supposé être "quelque chose d'exceptionnel dont vous devez être informé".

Il existe un moyen de rediriger stderr vers un fichier - vous le faites avec la commande suivante (pas très intuitive):

gcc new.c &> myFile

&>est "raccourci bash" pour "tout rediriger". Comme l'a souligné @CharlesDuffy, le formulaire conforme POSIX est

gcc new.c > myFile 2>&1

Cela signifie "compiler 'new.c' et envoyer stdoutà myFile. Et envoyer stderr(2) au même endroit que stdout( &1=" au même endroit que stdout ").

Vous trouverez plus de détails sur les différentes redirections sur http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-3.html et http://mywiki.wooledge.org/BashFAQ/055

Soit dit en passant, si vous souhaitez envoyer quelque chose depuis votre programme spécifiquement vers stderr, vous pouvez le faire avec les éléments suivants

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

Si vous incluez cela dans un programme, exécutez le programme et envoyez la sortie "normale" à un fichier, cela apparaîtra toujours sur la console. Donc, si vous compilez ce qui précède dans l'exécutable urgent, tapez

./urgent > /dev/null

à la console, votre sortie apparaîtra à l'écran.

Floris
la source
2
mywiki.wooledge.org/BashFAQ/055 est probablement une meilleure introduction à la redirection. De plus, il faut vraiment introduire le formulaire compatible POSIX ( >myFile 2>&1) ainsi que l'extension bash ( &>).
Charles Duffy
@CharlesDuffy - les deux très bons points. Je les inclurai dans ma réponse pour être complet.
Floris
11

Étant donné que les >redirections ne concernent que la sortie standard et que les erreurs sont écrites stderr, vous devez utiliser l'une des options suivantes à la place:

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

...ou...

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

&>est une extension BASH qui redirige à la fois stdoutet stderrvers un fichier; autrement, la meilleure approche est d'abord stdout redirect ( >temp.txt), puis faire stderr (FD 2) une copie du descripteur de fichier déjà redirigé sur la sortie standard (FD 1), comme suit: 2>&1.

nims
la source
4

Comme les autres l'ont dit, Linux fournit deux flux de sortie différents:

stdout , ou "sortie standard", est l'endroit où toutes les sorties normales vont.
              Vous pouvez le référencer en utilisant un descripteur de fichier 1.

stderr , ou "erreur standard" est un flux distinct pour les informations hors bande.
              Vous pouvez le référencer en utilisant un descripteur de fichier 2.

Pourquoi deux flux de sortie différents? Considérons un pipeline de commandes imaginaires:

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

Imaginez maintenant que la decryptcommande échoue et génère un message d'erreur. S'il envoyait ce message à stdout, il serait envoyé dans le tuyau, et à moins qu'il n'ait le mot «secret», vous ne le verriez jamais. Vous vous retrouveriez donc avec un fichier de sortie vide, sans aucune idée de ce qui n'allait pas.

Cependant, puisque le canal capture uniquement stdout, la decryptcommande peut envoyer ses erreurs à l' stderrendroit où elles seront affichées sur la console.

Vous pouvez rediriger stdoutet stderr, ensemble ou indépendamment:

# 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

Vous pouvez rediriger les erreurs stdoutet les traiter comme s'il s'agissait d'une sortie normale:

# 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

Vous pouvez également utiliser une notation "abrégée" pour rediriger à la fois stdout et stderr vers le même fichier:

decrypt $MY_FILE &> output.txt

Enfin, l' >opérateur tronquera d' abord son fichier de sortie avant d'y écrire. Si, à la place, vous souhaitez ajouter des données à un fichier existant, utilisez l' >>opérateur:

decrypt $MY_FILE 2>> more_errors.txt >> more_secrets.txt
decrypt $MY_FILE >> more_output.txt 2>&1
Adam Liss
la source
1
Deux petits reproches: (1) L'utilisation d'extensions de paramètres sans guillemets ( $FOO) est une source courante de bogues, et la démontrer dans les exemples n'est pas si génial. (2) L'utilisation de noms de variables tout en majuscules est la principale raison des conflits d'espace de noms entre l'environnement et les variables intégrées (majuscules par convention) et les variables locales (minuscules par convention). (3) Encourager les gens à utiliser à plusieurs reprises >>(qui rouvre le fichier chaque fois qu'il est utilisé dans une commande) plutôt que d'ouvrir un fichier une fois et de laisser le descripteur de fichier ouvert pour une utilisation par plusieurs commandes entraîne un code inefficace.
Charles Duffy
... sur le dernier point, comparez à: exec 4>secrets; echo "this is a secret" >&4; echo "this is another secret" >&4
Charles Duffy
+1 Merci de me garder honnête, @CharlesDuffy. Tous les bons points. J'ai intentionnellement omis execpour des raisons de simplicité, bien que dans la pratique, ce soit généralement une meilleure stratégie.
De plus, peuvent être réduits à ou (où il doit y avoir des espaces avant et après , et avant ). command₁ > output_file ; command₂ >> the_same_output_file( command₁ ; command₂ )  > output_file{ command₁ ; command₂ ;  }  > output_file{;}
G-Man dit `` Réintègre Monica '' le