web-dev-qa-db-fra.com

Dans Shell, que signifie "2> & 1"?

Dans un shell Unix, si je souhaite combiner stderr et stdout dans le flux stdout pour une manipulation ultérieure, je peux ajouter ce qui suit à la fin de ma commande:

2>&1

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

g++ lots_of_errors 2>&1 | head

je ne peux donc voir que les premières erreurs.

J'ai toujours du mal à me souvenir de cela, et je dois constamment chercher, et c'est principalement parce que je ne comprends pas bien la syntaxe de ce truc en particulier.

Quelqu'un peut-il casser cela et expliquer caractère par caractère ce que 2>&1 signifie?

2061

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

Voici un moyen de se souvenir de cette construction (bien que ce ne soit pas tout à fait exact): au début, 2>1 peut sembler être un bon moyen de rediriger stderr vers stdout. Cependant, cela sera en réalité interprété comme "rediriger stderr vers un fichier nommé 1". & indique que ce qui suit est un descripteur de fichier et non un nom de fichier. La construction devient alors: 2>&1.

2288
Ayman Hourieh
echo test > afile.txt

redirige la sortie standard vers afile.txt. C'est comme faire

echo test 1> afile.txt

Pour rediriger stderr, vous faites:

echo test 2> afile.txt

>& est la syntaxe pour rediriger un flux vers un autre descripteur de fichier: 0 correspond à stdin, 1 à stdout et 2 à stderr.

Vous pouvez rediriger stdout vers stderr en procédant comme suit:

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

Ou vice versa:

echo test 2>&1

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

566
dbr

Quelques astuces sur la redirection

Certaines particularités syntaxiques à ce sujet peuvent avoir des comportements importants. Il existe quelques exemples concernant les redirections, STDERR, STDOUT et les arguments ordering.

1 - Remplacer ou ajouter?

Symbole _>_ moyenne redirection .

  • _>_ mean envoie à un fichier complet , écrasant la cible si elle existe (voir noclobber fonctionnalité bash à # 3 plus tard).
  • _>>_ mean envoyer en plus de serait ajouté à la cible s'il existait.

Dans tous les cas, le fichier serait créé s'il n'existait pas.

2 - La ligne de commande du shell dépend de l’ordre !!

Pour tester cela, nous avons besoin d'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’ayez pas de répertoire nommé _/tnt_, bien sûr;). Eh bien, nous l'avons !!

Alors voyons:

_$ 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 affiche STDERR sur la console, et il ne semble pas que ce soit le comportement attendu ... Mais ...

Si vous souhaitez effectuer un filtrage postérieur sur une sortie, l’autre 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 --->
_

Notez 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 semble pas être le comportement attendu (alors, cela pourrait même être un comportement attendu) .

Eh bien, il existe quelques astuces sur les 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 apparaît spontanément à cause 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 en 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 passe par un filtre spécifique, STDERR vers un autre et enfin les deux sorties fusionnées passent par un troisième filtre de commande.

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

C'est à peu près écrasement:

Alors que _set -o noclobber_ donne instruction à bash de not ​​écraser tout fichier existant, la syntaxe _>|_ vous permet de surmonter cette limitation:

_$ 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, bon 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 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 se renseigner s’il est déjà défini.

_$ 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 sortie d'une commande donnée, nous voyons qu'une syntaxe correcte pourrait être:

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

pour ce cas spécial , il existe une syntaxe de raccourci: _&>_ ... ou _>&_

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

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

Remarque: si 2>&1 existe, 1>&2 est également une syntaxe correcte:

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

4b- Maintenant, je vais vous laisser penser à:

_$ 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 plus d'informations

Vous pouvez lire le manuel en tapant:

_man -Len -Pless\ +/^REDIRECTION bash
_

dans une console bash ;-)

300
F. Hauri

J'ai trouvé ce post brillant sur la redirection: Tout sur les redirections

Redirige la sortie standard et l'erreur standard vers un fichier

$ commande &> fichier

Cette ligne utilise l’opérateur &> pour rediriger les deux flux de sortie - stdout et stderr - d’une commande à l’autre. C'est le raccourci de Bash pour rediriger rapidement les deux flux vers la même destination.

Voici à quoi ressemble la table de descripteur de fichier après la redirection des deux flux par Bash:

Enter image description here

Comme vous pouvez le constater, stdout et stderr désignent maintenant file. Donc, tout ce qui est écrit sur stdout et stderr est écrit sur file.

Il existe plusieurs façons de rediriger les deux flux vers la même destination. Vous pouvez rediriger chaque flux les uns après les autres:

$ commande> fichier 2> & 1

C'est un moyen beaucoup plus courant de rediriger les deux flux vers un fichier. D'abord, stdout est redirigé vers le fichier, puis stderr est dupliqué pour être identique à stdout. Donc, les deux flux finissent par pointer vers file.

Lorsque Bash voit plusieurs redirections, il les traite de gauche à droite. Passons en revue les étapes et voyons comment cela se passe. Avant d'exécuter des commandes, le tableau de descripteur de fichier de Bash ressemble à ceci:

Enter image description here

Maintenant, Bash traite le premier fichier de redirection>. Nous avons déjà vu cela auparavant et cela fait stdout point to file:

Enter image description here

Next Bash voit la deuxième redirection 2> & 1. Nous n'avons pas vu cette redirection auparavant. Celui-ci duplique le descripteur de fichier 2 pour être une copie du descripteur de fichier 1 et nous obtenons:

Enter image description here

Les deux flux ont été redirigés vers le fichier.

Cependant soyez prudent ici! L'écriture

commande> fichier 2> & 1

n'est pas la même chose que d'écrire:

$ commande 2> & 1> fichier

L'ordre des redirections est important dans Bash! Cette commande redirige uniquement la sortie standard vers le fichier. Le stderr continuera d’imprimer sur le terminal. Pour comprendre pourquoi cela se produit, reprenons les étapes. Donc avant d'exécuter la commande, la table de descripteur de fichier ressemble à ceci:

Enter image description here

Bash traite maintenant les redirections de gauche à droite. Il voit d’abord 2> & 1 pour dupliquer stderr sur stdout. La table de descripteur de fichier devient:

Enter image description here

Bash voit maintenant la deuxième redirection, >file, et redirige stdout vers fichier:

Enter image description here

Voyez-vous ce qui se passe ici? Stdout pointe maintenant sur fichier, mais stderr pointe toujours sur le terminal! Tout ce qui est écrit sur stderr est toujours imprimé à l'écran! Alors soyez très très prudent avec l'ordre des redirections!

Notez également que dans Bash, l'écriture

$ commande &> fichier

est exactement le même que:

$ commande> & file

93
Deen John

Les chiffres renvoient aux descripteurs de fichier (fd).

  • Zéro est stdin
  • On est stdout
  • Deux est stderr

2>&1 redirige fd 2 vers 1.

Cela fonctionne pour n'importe quel nombre de descripteurs de fichiers si le programme les utilise.

Vous pouvez regarder /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 fichier non standard pour la journalisation personnalisée afin que vous ne les voyiez pas, sauf si vous le redirigiez vers un fichier ou quelque chose du genre.

77
Colin Burnett

Cette construction envoie le flux d'erreur standard (stderr) à l'emplacement actuel de la sortie standard (stdout) - ce problème de devise semble avoir été négligé par les autres réponses.

Vous pouvez rediriger n'importe quel handle de sortie vers un autre à l'aide de cette méthode, mais elle est le plus souvent utilisée pour canaliser les flux stdout et stderr dans un seul flux à des fins de traitement.

Certains exemples sont:

# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR

# Run the less pager without stderr screwing up the output.
foo 2>&1 | less

# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile

# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2

Notez que ce dernier va pas diriger stderr vers outfile2 - il le redirige vers ce que stdout était lorsque l'argument a été rencontré (outfile1) et alors redirige stdout vers outfile2.

Cela permet des ruses assez sophistiquées.

54
paxdiablo

2>&1 est une construction POSIX Shell. Voici une ventilation, jeton par jeton:


2: " Erreur type " descripteur du fichier de sortie.

>&: () dupliquer un descripteur de fichier de sortie (une variante de Redirection de sortie opérateur >). Étant donné [x]>&[y], le descripteur de fichier désigné par x est conçu pour être une copie du descripteur de fichier de sortie y.

1 " Sortie standard " descripteur de fichier de sortie.

L'expression 2>&1 copie le descripteur de fichier 1 vers l'emplacement 2, de sorte que toute sortie écrite dans 2 ("erreur standard") dans l'environnement d'exécution est identique au fichier décrit à l'origine. par 1 ("sortie standard").


Plus d'explications:

Descripteur de fichier : "Un entier non négatif unique par processus utilisé pour identifier un fichier ouvert aux fins du fichier. accès."

Sortie standard/erreur : reportez-vous à la remarque suivante dans la section Redirection de la documentation du shell:

Les fichiers ouverts sont représentés par des nombres décimaux commençant par zéro. La plus grande valeur possible est définie par l'implémentation; Cependant, toutes les mises en œuvre doivent prendre en charge au moins 0 à 9 inclus, pour une utilisation par l'application. Ces nombres sont appelés "descripteurs de fichier". Les valeurs 0, 1 et 2 ont une signification spéciale et des utilisations conventionnelles et sont impliquées par certaines opérations de redirection; ils sont appelés entrée standard, sortie standard et erreur standard, respectivement. Les programmes utilisent généralement l'entrée standard et écrivent la sortie sur la sortie standard. Les messages d'erreur sont généralement écrits sur une erreur standard. Les opérateurs de redirection peuvent être précédés d'un ou de plusieurs chiffres (sans caractères intermédiaires autorisés) pour désigner le numéro du descripteur de fichier.

18
wjordan

2 est l'erreur standard de la console.

1 est la sortie standard de la console.

C'est le standard Unix, et Windows suit également le POSIX.

Par exemple. quand tu cours

Perl test.pl 2>&1

l'erreur standard est redirigé vers la sortie standard, vous pouvez ainsi voir les deux sorties ensemble:

Perl test.pl > debug.log 2>&1

Après exécution, vous pouvez voir toutes les sorties, y compris les erreurs, dans le fichier debug.log.

Perl test.pl 1>out.log 2>err.log

Ensuite, la sortie standard passe à out.log et l'erreur type à err.log.

Je vous suggère d'essayer de les comprendre.

17
Marcus Thornton

Pour répondre à votre question: il faut toute sortie d'erreur (normalement envoyée à stderr) et l'écrit sur la sortie standard (stdout).

Ceci est utile avec, par exemple, "plus" lorsque vous avez besoin de la pagination pour toutes les sorties. Certains programmes, tels que l’impression des informations d’utilisation dans stderr.

Pour vous aider à vous souvenir

  • 1 = sortie standard (où les programmes impriment une sortie normale)
  • 2 = erreur standard (où les programmes impriment des erreurs)

"2> & 1" pointe simplement tout ce qui est envoyé à stderr, à stdout à la place.

Je recommande également de lire cet article sur la redirection des erreurs où ce sujet est couvert en détail.

16
Andrioid

Du point de vue du programmeur, cela signifie précisément ceci:

dup2(1, 2);

Voir le page de manuel .

Comprendre que 2>&1 est une copie explique aussi pourquoi ...

command >file 2>&1

... n'est pas la même chose que ...

command 2>&1 >file

Le premier enverra les deux flux à file, tandis que le second enverra les erreurs à stdout et la sortie ordinaire à file.

11
ams

À condition que /foo n’existe pas sur votre système et que /tmp ne…

$ ls -l /tmp /foo

va imprimer le contenu de /tmp et afficher un message d'erreur pour /foo

$ ls -l /tmp /foo > /dev/null

enverra le contenu de /tmp à /dev/null et affichera un message d'erreur pour /foo

$ ls -l /tmp /foo 1> /dev/null

fera exactement la même chose (notez le 1)

$ ls -l /tmp /foo 2> /dev/null

va imprimer le contenu de /tmp et envoyer le message d'erreur à /dev/null

$ ls -l /tmp /foo 1> /dev/null 2> /dev/null

enverra à la fois la liste et le message d'erreur à /dev/null

$ ls -l /tmp /foo > /dev/null 2> &1

est un raccourci

6
Matijs

Souvenez-vous toujours de l'indication de paxdiablo concernant l'emplacement actuel de la cible de la redirection ... Il est important.

Mon mnémonique personnelle pour l'opérateur 2>&1 est la suivante:

  • Pensez à & comme signifiant 'and' ou 'add' (le caractère est un ampère - et , n'est-ce pas?)
  • Ainsi, il devient: 'redirige 2 (stderr) vers où 1 (stdout) est déjà/est actuellement et ajout les deux flux' .

Le même mnémonique fonctionne également pour l'autre redirection fréquemment utilisée, 1>&2:

  • Pensez à & signifiant and ou add... (vous avez une idée de l'esperluette, oui?)
  • Ainsi, il devient: 'redirige 1 (sortie standard) vers où 2 (stderr) est déjà/est actuellement et ajout les deux flux' .

Et rappelez-vous toujours: vous devez lire les chaînes de redirections 'de la fin', de droite à gauche (not de gauche à droite).

6
Kurt Pfeifle

Cela revient à transmettre l'erreur à la sortie standard ou au terminal.

C'est-à-dire que cmd n'est pas une commande:

$cmd 2>filename
cat filename

command not found

L'erreur est envoyée au fichier comme ceci:

2>&1

L'erreur standard est envoyée au terminal.

5
Kalanidhi

Redirection d'entrée

La redirection d’entrée entraîne l’ouverture du fichier dont le nom résulte de l’extension de Word en lecture sur le descripteur de fichier n, ou l’entrée standard (descripteur de fichier 0) si n n’est pas spécifié.

Le format général pour rediriger les entrées est le suivant:

[n]<Word

Redirection de sortie

La redirection de la sortie entraîne l’ouverture du fichier dont le nom résulte de l’expansion de Word en écriture sur le descripteur de fichier n, ou la sortie standard (descripteur de fichier 1) si n n’est pas spécifié. Si le fichier n'existe pas, il est créé. s'il existe, il est tronqué à une taille nulle.

Le format général pour rediriger la sortie est:

[n]>Word

Déplacement de descripteurs de fichiers

L'opérateur de redirection,

[n]<&digit-

déplace le chiffre du descripteur de fichier vers le descripteur de fichier n ou l'entrée standard (descripteur de fichier 0) si n n'est pas spécifié. le chiffre est fermé après avoir été dupliqué en n.

De même, l'opérateur de redirection

[n]>&digit-

déplace le chiffre du descripteur de fichier vers le descripteur de fichier n ou la sortie standard (descripteur de fichier 1) si n n'est pas spécifié.

Ref:

man bash

Tapez /^REDIRECT pour localiser la section redirection et en savoir plus ...

Une version en ligne est ici: .6 Redirections

PS:

La plupart du temps, man était le puissant outil pour apprendre Linux.

4
yurenchen

0 pour l'entrée, 1 pour stdout et 2 pour stderr.

n conseil: somecmd >1.txt 2>&1 est correct, tandis que somecmd 2>&1 >1.txt est totalement faux sans effet!

1
fzyzcjy