2938 votes

Dans le shell, que signifie " 2>&1 " ?

Dans un shell Unix, si je veux combiner stderr y stdout dans le stdout pour une manipulation plus poussée, je peux ajouter le texte suivant à la fin de ma commande :

2>&1

Donc, si je veux utiliser head sur la sortie de g++ je peux faire quelque chose comme ça :

g++ lots_of_errors 2>&1 | head

pour que je ne puisse voir que les premières erreurs.

J'ai toujours du mal à m'en souvenir, et je dois constamment le chercher. C'est surtout parce que je ne comprends pas bien la syntaxe de cette astuce particulière.

Quelqu'un pourrait-il nous expliquer, personnage par personnage, ce que 2>&1 signifie ?

61 votes

@dbr Je ne pense pas que ce soit seulement bash - je crois que c'est un truc de bourne shell ; d'où sh, bash, ksh, ash, dash, etc.

8 votes

Ceci fait partie du paragraphe de redirection décrivant les shells compatibles POSIX, ou shell POSIX en abrégé. ksh est un shell POSIX par exemple. Voir : pubs.opengroup.org/onlinepubs/009695399/utilités/

15 votes

Cette construction fonctionne également sous Windows.

3271voto

Ayman Hourieh Points 39435

Le descripteur de fichier 1 est la sortie standard ( stdout ).
Le descripteur de fichier 2 est l'erreur standard ( stderr ).

Voici une façon de se souvenir de cette construction (bien qu'elle ne soit pas tout à fait exacte) : au début, 2>1 peut sembler être un bon moyen de rediriger stderr a stdout . Cependant, il sera en fait interprété comme "rediriger". stderr dans un fichier nommé 1 ". & indique que ce qui suit et précède est un descripteur de fichier et non un nom de fichier. La construction devient donc : 2>&1 .

Pensez à >& comme opérateur de fusion par réorientation.

1 votes

Est-ce que cela a un sens pour vous ? java... 2&1 >> data.log J'ai vu un de mes collègues faire ça

3 votes

>> signifie ajouter la sortie au fichier data.log.

3 votes

@ThangPham signifie STDOUT ajouté à data.log et STDERR vidée vers STDOUT (console ou commande suivante) voir ma réponse

881voto

dbr Points 66401
echo test > afile.txt

redirige stdout vers afile.txt . C'est la même chose que de faire

echo test 1> afile.txt

Pour rediriger stderr, vous faites :

echo test 2> afile.txt

Alors >& est la syntaxe pour rediriger a flux à un autre descripteur de fichier :

  • 0 est stdin
  • 1 est stdout
  • 2 est stderr

Vous pouvez rediriger stdout vers stderr en faisant :

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

Ou vice versa :

echo test 2>&1

Donc, en résumé... 2> redirige stderr vers un fichier (non spécifié), en y ajoutant &1 redirige stderr vers stdout.

6 votes

Est-ce que cela a un sens pour vous ? java ... 2&1 >> data.log J'ai vu un de mes collègues faire ça

7 votes

@Harry cela ressemble soit à un shell qui n'est pas bash, soit à une faute de frappe . cmd 2>&1 >> somefile.log ajoutera stdout/stderr à un fichier - c'est fondamentalement la même chose que ci-dessus, avec >> file pour ajouter

105 votes

@dbr cmd 2>&1 >>file ne redirige pas stderr vers le fichier, mais cmd >> file 2>&1 fait. L'ordre est important. Dans le premier cas, stderr est redirigé vers le stdout du shell (éventuellement un tty si la commande est entrée de manière interactive), puis stdout est dirigé vers le fichier. Dans le second cas, stdout est dirigé vers le fichier, puis stderr est dirigé vers le même endroit.

397voto

F. Hauri Points 5893

Quelques astuces sur la redirection

Une certaine particularité syntaxique à ce sujet peut avoir des comportements importants. Il y a quelques petits échantillons sur les redirections, STDERR , STDOUT et des arguments commander .

1 - Écraser ou annexer ?

Symbole > signifie redirection .

  • > signifie envoyer à un fichier complet en écrasant la cible si elle existe (voir noclobber fonction bash à #3 plus tard).
  • >> signifie envoyer en plus de s'ajoutera à la cible si elle existe.

Dans tous les cas, le fichier sera créé s'il n'existe pas.

2 - Le ligne de commande shell

Pour tester cela, nous avons besoin de une commande simple qui enverra quelque chose sur les deux sorties :

$ 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

(En supposant que vous n'avez pas un répertoire nommé /tnt bien sûr ;). Eh bien, nous l'avons !

Alors, voyons voir :

$ 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

La dernière ligne de commande vide STDERR à la console, et il semble que ce ne soit pas le comportement attendu... Mais...

Si vous voulez en faire post-filtrage à propos de standard sortie, erreur ou les deux :

$ 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 --->

Remarquez que la dernière ligne de commande dans ce paragraphe est exactement la même que dans le paragraphe précédent, où j'ai écrit ne semblent pas être le comportement attendu (donc, cela pourrait même être un comportement attendu).

Eh bien, il y a un petit truc à propos des redirections, pour faire une opération différente sur les deux sorties :

$ ( 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 : &9 descripteur se produirait spontanément en raison de ) 9>&2 .

Addendum : nota ! Avec la nouvelle version de bash ( >4.0 ), il existe une nouvelle fonctionnalité et une syntaxe plus sexy pour faire ce genre de choses :

$ 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

Et enfin pour un tel formatage de sortie en cascade :

$ ((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 ! Même nouvelle syntaxe, dans les deux sens :

$ 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

STDOUT passent par un filtre spécifique, STDERR vers un autre et enfin les deux sorties fusionnées passent par un troisième filtre de commande.

2b - Utilisation |& au lieu de

Syntaxe command |& ... pourrait être utilisé comme un alias para command 2>&1 | ... . Les mêmes règles concernant l'ordre des lignes de commande s'appliquent. Plus de détails à Quelle est la signification de l'opérateur |& en bash ?

3 - Un mot sur noclobber et l'option >| syntaxe

C'est à peu près écrasement :

Alors que set -o noclobber demander à bash de no écraser tout fichier existant, le >| La syntaxe vous permet de franchir cette limite :

$ 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

Le fichier est écrasé à chaque fois, et bien maintenant :

$ 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

Passez à travers avec >| :

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:18:58 CET 2013

$ date >| $testfile ; cat $testfile
Mon Jan  7 13:19:01 CET 2013

Désactiver cette option et/ou demander si elle est déjà activée.

$ 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 - Dernier tour et plus...

Pour rediriger les deux la sortie d'une commande donnée, nous voyons qu'une syntaxe correcte pourrait être :

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

pour cette spécial Dans ce cas, il existe une syntaxe raccourcie : &> ... ou >&

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

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

Nota : si 2>&1 existent, 1>&2 est également une syntaxe correcte :

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

4b- Maintenant, je vais vous laisser réfléchir :

$ 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- Si vous êtes intéressé par más information

Vous pouvez lire le manuel détaillé en cliquant ici :

man -Len -Pless\ +/^REDIRECTION bash

dans un bash console ;-)

6 votes

Pour en savoir plus : Si vous avez aimé ceci, vous apprécierez peut-être : Comment l'abus de redirection peut donner lieu à des comportements étranges

1 votes

118voto

Colin Burnett Points 4572

Les numéros font référence aux descripteurs de fichiers (fd).

  • Zéro est stdin
  • L'un est stdout
  • Deux est stderr

2>&1 redirige le fd 2 vers le 1.

Cela fonctionne pour un nombre quelconque de descripteurs de fichiers si le programme les utilise.

Vous pouvez consulter /usr/include/unistd.h si vous les oubliez :

/* Standard file descriptors.  */
#define STDIN_FILENO    0   /* Standard input.  */
#define STDOUT_FILENO   1   /* Standard output.  */
#define STDERR_FILENO   2   /* Standard error output.  */

Cela dit, j'ai écrit des outils en C qui utilisent des descripteurs de fichiers non standard pour la journalisation personnalisée, de sorte que vous ne la voyez pas, sauf si vous la redirigez vers un fichier ou autre.

104voto

Bill Karwin Points 204877
  • 2 est le descripteur de fichier par défaut pour stderr.
  • 1 est le descripteur de fichier par défaut pour stdout.
  • >& est la syntaxe shell pour "replier le précédent (premier) descripteur de fichier dans le prochain (deuxième) descripteur de fichier".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X