commande sh: exec 2 > & 1
5 réponses
Techniquement parlant, il duplique, ou copie, stderr sur stdout.
Généralement, vous n'avez pas besoin de l'exec pour effectuer cela. Une utilisation plus typique d'exec avec des descripteurs de fichier est d'indiquer que vous souhaitez attribuer un fichier à un descripteur de fichier inutilisé, par exemple
exec 35< my_input
BTW N'oubliez pas que la séquence de déclaration lors de la redirection vers un fichier est importante, donc
ls > mydirlist 2>&1
Fonctionnera car il dirige à la fois stdout et stderr vers le fichier mydirlist, alors que le commande
ls 2>&1 > mydirlist
Dirige uniquement stdout, et non stderr, vers le fichier mydirlist, car stderr a fait une copie de stdout avant que stdout ne soit redirigé vers mydirlist.
Edit: c'est la façon dont le shell fonctionne en scannant de gauche à droite. Alors lisez le second comme disant "copier stderr sur stdout" avant de dire "envoyer stdout à mydirlist". Ensuite, lisez le premier comme disant "envoyer stdout au fichier mydirlist" avant de dire "dupliquer stderr sur ce stdout que j'ai mis en place". Je savoir. C'est absolument pas intuitif!
L'un des meilleurs articles que j'ai vu sur ce que" 2>&1 " fait est Bash One-Liners Explained, Part III: All about redirections .
Mais ce que les réponses actuelles sur cette question ne parviennent pas à fournir, c'est pourquoi vous voudriez le faire après un simple "exec". Comme l'explique la page de manuel bash pour la commande exec: "si la commande n'est pas spécifiée, toutes les redirections prennent effet dans le shell actuel".
J'ai écrit un script simple appelé {[4] } qui écrit une ligne de sortie vers stdout, et une autre ligne vers stderr:
#!/usr/bin/python
import sys
sys.stdout.write('this is stdout.\n')
sys.stderr.write('this is stderr.\n')
Et puis j'ai enveloppé cela dans un script shell appelé out-and-err.sh avec un "exec 2> & 1":
#!/bin/bash
exec 2>&1
./out-and-err.py
Si je lance juste le script python, stdout et stderr sont séparés:
$ ./out-and-err.py 1> out 2> err
$ cat out
this is stdout.
$ cat err
the is stderr.
Mais si j'exécute le script shell, vous pouvez voir que l'exec s'occupe de stderr pour tout après:
$ ./out-and-err.sh 1> out 2> err
$ cat out
this is stdout.
this is stderr.
$ cat err
$
Si votre script shell d'emballage fait beaucoup plus que la seule commande python, et que vous avez besoin de toutes les sorties combinées dans stdout, faire le "exec 2> & 1" fera que facile pour vous.
Il lie l'erreur standard à la sortie standard
Le 2
est stderr et 1
est la sortie standard stdout. Lorsque vous exécutez un programme, vous obtiendrez la sortie normale dans stdout, mais les erreurs ou les Avertissements vont généralement à stderr. Si vous voulez acheminer toutes les sorties vers un fichier par exemple, il est utile de combiner d'abord stderr avec stdout avec 2>&1
.
Comme l'a dit @cma, il met stderr sur stdout. La raison pour laquelle vous pouvez vouloir ce comportement est d'utiliser grep ou tout autre utilitaire pour capturer la sortie qui apparaît uniquement sur stderr. Ou vous pouvez simplement enregistrer toute la sortie, y compris stderr, dans un fichier pour un traitement ultérieur.
Une application très utile de exec 2>&1
que j'ai rencontrée est quand vous voulez fusionner stderr
et stdout
pour plusieurs commandes séparées par des points-virgules. Mon exemple particulier est arrivé quand j'envoyais plus d'une commande à popen
en PHP et je voulais voir les erreurs entrelacées comme vous le verriez si vous tapiez les commandes à une invite shell:
$ echo hi ; yikes ; echo there
hi
-bash: yikes: command not found
there
$
Ce qui suit ne fusionne pas stderr
et stdout
sauf pour le dernier echo
(ce qui est inutile car le yikes
provoque le erreur):
echo hi ; yikes ; echo there 2>&1
Je peux obtenir la sortie fusionnée à la "dure" comme suit:
echo hi 2>&1; yikes 2>&1; echo there 2>&1
Il semble beaucoup plus propre et moins sujet aux erreurs si vous utilisez exec
:
exec 2>&1 ; echo hi; echo yikes; echo there
Vous obtenez la sortie stdout
et stderr
bien entrelacée exactement comme vous le verriez sur le terminal si vous exécutiez les trois commandes séparées par un point-virgule.