Comment rediriger et ajouter à la fois stdout et stderr à un fichier avec Bash?

1535

Pour rediriger stdout vers un fichier tronqué dans Bash, je sais utiliser:

cmd > file.txt

Pour rediriger stdout dans Bash, en ajoutant à un fichier, je sais utiliser:

cmd >> file.txt

Pour rediriger à la fois stdout et stderr vers un fichier tronqué, je sais utiliser:

cmd &> file.txt

Comment rediriger stdout et stderr en ajoutant un fichier? cmd &>> file.txtN'a pas travaillé pour moi.

fil volant
la source
37
Je voudrais noter que &> outfile est un code spécifique à Bash (et autres) et non portable. La façon de devenir portable (similaire aux réponses en annexe) a toujours été et est toujours> outfile 2> & 1
TheBonsai

Réponses:

1999
cmd >>file.txt 2>&1

Bash exécute les redirections de gauche à droite comme suit:

  1. >>file.txt: Ouvrir file.txten mode ajout et stdouty rediriger .
  2. 2>&1: Rediriger stderrvers "où stdoutva actuellement" . Dans ce cas, il s'agit d'un fichier ouvert en mode ajout. En d'autres termes, le &1réutilise le descripteur de fichier qui stdoututilise actuellement.
Alex Martelli
la source
33
fonctionne très bien! mais y a-t-il un moyen de donner un sens à cela ou dois-je le traiter comme une construction bash atomique?
flybywire
181
C'est une redirection simple, les instructions de redirection sont évaluées, comme toujours, de gauche à droite. >> fichier: Rouge. STDOUT au fichier (mode ajout) (abréviation de 1 >> fichier) 2> & 1: rouge. STDERR vers "où va stdout" Notez que l'interprétation "rediriger STDERR vers STDOUT" est incorrecte.
TheBonsai
31
Il dit "ajouter la sortie (stdout, descripteur de fichier 1) sur file.txt et envoyer stderr (descripteur de fichier 2) au même endroit que fd1".
pause jusqu'à nouvel ordre.
2
@TheBonsai cependant, si j'ai besoin de rediriger STDERR vers un autre fichier mais en y ajoutant? Est-ce possible?
2013
41
si vous le faites, vous cmd >>file1 2>>file2devriez obtenir ce que vous voulez.
Woodrow Douglass
367

Il existe deux façons de le faire, selon votre version de Bash.

La manière classique et portable ( Bash pré-4 ) est:

cmd >> outfile 2>&1

Une manière non portable, à commencer par Bash 4 est

cmd &>> outfile

(analogue à &> outfile)

Pour un bon style de codage, vous devez

  • décider si la portabilité est un problème (puis utiliser la méthode classique)
  • décider si la portabilité même vers Bash pré-4 est un problème (puis utiliser de manière classique)
  • peu importe la syntaxe que vous utilisez, ne la modifiez pas dans le même script (confusion!)

Si votre script commence déjà par #!/bin/sh(que ce soit voulu ou non), la solution Bash 4, et en général tout code spécifique à Bash, n'est pas la voie à suivre.

Rappelez-vous également que Bash 4 &>>est juste une syntaxe plus courte - il n'introduit aucune nouvelle fonctionnalité ou quelque chose comme ça.

La syntaxe est (à côté d'une autre syntaxe de redirection) décrite ici: http://bash-hackers.org/wiki/doku.php/syntax/redirection#appending_redirected_output_and_error_output

TheBonsai
la source
8
Je préfère & >> car il est cohérent avec &> et >>. Il est également plus facile de lire «ajouter la sortie et les erreurs à ce fichier» que «envoyer les erreurs à la sortie, ajouter la sortie à ce fichier». Notez que Linux a généralement une version actuelle de bash, OS X, au moment de la rédaction, nécessite toujours que bash 4 soit installé manuellement via homebrew, etc.
mikemaccana
Je l'aime plus car il est plus court et ne compte que deux places par ligne, alors que ferait par exemple zsh avec "& >>"?
Phillipp
Il est également important de noter que dans un travail cron, vous devez utiliser la syntaxe pré-4, même si votre système a Bash 4.
hyperknot
5
@zsero cron n'utilise pas du tout bash ... il l'utilise sh. Vous pouvez modifier le shell par défaut en ajoutant SHELL=/bin/bashau début le crontab -efichier.
Ray Foss
89

Dans Bash, vous pouvez également spécifier explicitement vos redirections vers différents fichiers:

cmd >log.out 2>log_error.out

Ajouter serait:

cmd >>log.out 2>>log_error.out
Aaron R.
la source
6
En redirigeant deux flux vers le même fichier à l'aide de votre première option, le premier écrira «au-dessus» du second, écrasant tout ou partie du contenu. Utilisez plutôt cmd >> log.out 2> log.out .
Orestis P.
3
Merci d'avoir attrapé ça; vous avez raison, l'un va écraser l'autre. Cependant, votre commande ne fonctionne pas non plus. Je pense que la seule façon d'écrire dans le même fichier est celle qui a été donnée précédemment cmd >log.out 2>&1. J'édite ma réponse pour supprimer le premier exemple.
Aaron R.
65

Dans Bash 4 (ainsi que ZSH 4.3.11):

cmd &>>outfile

juste sorti de la boîte

UN B
la source
2
@all: c'est une bonne réponse, car cela fonctionne avec bash et est bref, j'ai donc édité pour m'assurer qu'il mentionne explicitement bash.
mikemaccana
10
@mikemaccana: La réponse de TheBonsai montre la solution bash 4 depuis 2009
jfs
52

Cela devrait fonctionner correctement:

your_command 2>&1 | tee -a file.txt

Il stockera tous les journaux dans file.txt ainsi que les vider sur le terminal.

Pradeep Goswami
la source
C'est la bonne réponse si vous souhaitez également voir la sortie dans le terminal. Cependant, ce n'était pas la question initialement posée.
Mikko Rantalainen
25

Essaye ça

You_command 1>output.log  2>&1

Votre utilisation de &> x.file fonctionne dans bash4. Désolé : (

Voici quelques conseils supplémentaires.

0, 1, 2 ... 9 sont des descripteurs de fichiers en bash.

0 signifie stdin, 1 signifie stdout, 2 signifie stderror. 3 ~ 9 est disponible pour toute autre utilisation temporaire.

Tout descripteur de fichier peut être redirigé vers un autre descripteur de fichier ou fichier à l'aide de l'opérateur >ou >>(ajouter).

Utilisation: < file_descriptor > > < nom de fichier | & file_descriptor >

Veuillez vous référer à http://www.tldp.org/LDP/abs/html/io-redirection.html

Quintus.Zhou
la source
Votre exemple fera quelque chose de différent de l'OP demandé: il redirigera le stderr de You_commandvers stdout et le stdout de You_commandvers le fichier output.log. De plus, il ne sera pas ajouté au fichier mais il le remplacera.
pabouk
Correct: le descripteur de fichier peut être n'importe quelle valeur supérieure à 3 pour tous les autres fichiers.
Itachi
5
Votre réponse montre l'erreur de redirection de sortie la plus courante: rediriger STDERR vers où STDOUT pointe actuellement et seulement après avoir redirigé STDOUT vers un fichier. Cela n'entraînera pas la redirection de STDERR vers le même fichier. L'ordre des redirections est important.
Jan Wikholm
1
cela signifie-t-il que je devrais d'abord rediriger STDERROR vers STDOUT, puis rediriger STDOUT vers un fichier. 1 > output.log 2>&1
Quintus.Zhou
1
@ Quintus.Zhou Yup. Votre version redirige l'erreur vers out et en même temps vers fichier.
Alex Yaroshevich
11

Je suis surpris que depuis près de dix ans, personne n'ait encore posté cette approche:

Si vous utilisez des versions plus anciennes de bash là où elles &>>ne sont pas disponibles, vous pouvez également faire:

(cmd 2>&1) >> file.txt

Cela génère un sous-shell, il est donc moins efficace que l'approche traditionnelle de cmd >> file.txt 2>&1, et cela ne fonctionnera donc pas pour les commandes qui doivent modifier le shell actuel (par exemple cd, pushd), mais cette approche me semble plus naturelle et compréhensible:

  1. Redirigez stderr vers stdout.
  2. Redirigez la nouvelle sortie standard en l'ajoutant à un fichier.

De plus, les parenthèses suppriment toute ambiguïté d'ordre, en particulier si vous souhaitez plutôt diriger stdout et stderr vers une autre commande.

jamesdlin
la source
Cette implémentation entraîne l'exécution d'un processus supplémentaire pour le système. L'utilisation de la syntaxe cmd >> file 2>&1fonctionne dans tous les shells et ne nécessite pas de processus supplémentaire pour s'exécuter.
Mikko Rantalainen
@MikkoRantalainen J'ai déjà expliqué qu'il engendre un sous-shell et est moins efficace. Le point de cette approche est que si l'efficacité n'est pas un gros problème (et c'est rarement le cas), cette façon est plus facile à retenir et plus difficile à se tromper.
jamesdlin