Dans le shell, que signifie «2 & 1»?
Question
Dans un shell Unix, si je veux 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
afin que je puisse voir que les premières erreurs.
J'ai toujours du mal à me souvenir de cela, et je dois constamment aller le chercher, principalement parce que je ne comprends pas bien la syntaxe de ce truc en particulier.
Quelqu'un peut-il expliquer cela et expliquer, caractère par caractère, ce que 2 > & amp; 1
signifie?
La solution
Le descripteur de fichier 1 est la sortie standard ( stdout
).
Le descripteur de fichier 2 correspond à l'erreur standard ( stderr
).
Voici un moyen de rappeler cette construction (bien que ce ne soit pas tout à fait précis): au début, 2 > 1
peut sembler être un bon moyen de rediriger stderr
vers stdout
. Cependant, il sera en réalité interprété comme "rediriger stderr
vers un fichier nommé 1
". & amp;
indique que ce qui suit est un descripteur de fichier et non un nom de fichier. La construction devient alors: 2 > & amp <1> code
.
Autres conseils
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 devez:
echo test 2> afile.txt
> & amp;
est la syntaxe permettant de rediriger un flux vers un autre descripteur de fichier: 0 correspond à stdin, 1 à stdout et 2 à stderr.
Vous pouvez rediriger stdout vers stderr en faisant:
echo test 1>&2 # or echo test >&2
Ou vice versa:
echo test 2>&1
En bref, 2 >
redirige stderr vers un fichier (non spécifié), en ajoutant & amp; 1 / code> redirige stderr vers stdout.
Quelques astuces sur la redirection
Certaines particularités syntaxiques à ce sujet peuvent avoir des comportements importants. Il existe quelques exemples de redirections, STDERR
, STDOUT
et des arguments ordering .
1 - Écraser ou ajouter?
Le symbole >
signifie redirection .
-
>
signifie envoyer à un fichier complet , écrasant la cible si elle existe (voirnoclobber
fonction bash à # 3 plus tard). -
> >
signifie que 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 est dépendante de l'ordre !!
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
(Dans l’espoir que vous n’ayez pas de répertoire nommé / tnt
, bien sûr;). Eh bien, nous l’avons!
Voyons donc:
$ 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. Il ne semble pas que ce soit le comportement attendu ... Mais ...
Si vous souhaitez effectuer un post-filtrage sur une sortie, sur l’autre ou sur 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 de ce paragraphe est identique à celle du paragraphe précédent. semble ne pas être le comportement attendu (donc, il pourrait même s'agir d'un comportement attendu).
Eh bien, il y a quelques astuces sur les redirections, pour 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
Remarque: le descripteur & 9
apparaîtrait spontanément en raison de ) 9 > & 2
.
Addendum: nota! Avec la nouvelle version de bash ( & 4.0
), une nouvelle fonctionnalité et une syntaxe plus sexy permettent de réaliser ce type de tâches:
$ 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 syntaxe nouvelle, 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
Où STDOUT
passe par un filtre spécifique, STDERR
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 l'écrasement :
Bien que set -o noclobber
demande à bash de ne pas remplacer les fichiers existants, la syntaxe > |
vous permet de franchir 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 encore ...
Pour rediriger les deux résultats 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: & amp; >
... ou > & amp;
$ ls -ld /tmp /tnt &>/dev/null
$ ls -ld /tmp /tnt >&/dev/null
Remarque: si 2 > & amp; 1
existent, 1 > & amp; 2
est une syntaxe correcte. aussi:
$ 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 plus d’informations
Vous pouvez lire le manuel en tapant:
man -Len -Pless\ +/^REDIRECTION bash
dans une bash console; -)
J'ai trouvé cet article génial sur la redirection: Tout sur les redirections
Rediriger la sortie standard et l'erreur standard vers un fichier
$ commande & amp; > fichier
Ce one-liner utilise l'opérateur & amp; >
pour rediriger les deux flux de sortie - stdout et stderr - de commande en fichier. C'est le raccourci de Bash pour rediriger rapidement les deux flux vers la même destination.
Voici à quoi ressemble le tableau de descripteur de fichier après la redirection des deux flux par Bash:
Comme vous pouvez le constater, stdout et stderr désignent maintenant le fichier
. Donc, tout ce qui est écrit sur stdout et stderr est écrit dans le fichier
.
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:
$ command > fichier 2 > & amp; 1
Il s'agit d'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. Ainsi, les deux flux finissent par pointer vers le fichier
.
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 se présente comme suit:
Maintenant, Bash traite le premier fichier > de redirection. Nous avons déjà vu cela auparavant et cela fait stdout point to file:
Next Bash voit la deuxième redirection 2 > & amp; 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:
Les deux flux ont été redirigés vers un fichier.
Cependant soyez prudent ici! Écriture
commande > fichier 2 > & amp; 1
n'est pas la même chose que d'écrire:
$ command 2 > & amp; 1 > file
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. Ainsi, avant d'exécuter la commande, la table de descripteur de fichier se présente comme suit:
Bash traite maintenant les redirections de gauche à droite. Il voit d’abord 2 > & 1; il duplique donc stderr sur stdout. La table de descripteur de fichier devient:
Bash voit maintenant la deuxième redirection, > fichier
, et redirige la sortie standard vers le fichier:
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 & amp; > fichier
est exactement le même que:
$ commande > & amp; fichier
Les numéros font référence aux descripteurs de fichier (fd).
- zéro est
stdin
- L'un est
stdout
- Deux est
stderr
2 > & amp; 1
redirige le dd 2 vers 1.
Ceci fonctionne pour un nombre quelconque de descripteurs de fichier 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 fichier non standard pour la journalisation personnalisée. Vous ne les voyez donc pas, à moins que vous ne les redirigiez vers un fichier ou quelque chose du genre.
Cette construction envoie le flux d'erreur standard ( stderr
) à l'emplacement actuel de la sortie standard ( stdout
) - ce problème de devise semble apparaître. ont été négligés par les autres réponses.
Vous pouvez rediriger n'importe quel handle de sortie vers un autre en utilisant 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.
Quelques exemples:
# 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 ne sera pas diriger stderr
vers fichier_ outfile2
- il le redirige vers ce que stdout
était lorsque l'argument a été rencontré ( outfile1
) et que then redirige stdout
vers outfile2
.
Cela permet des ruses assez sophistiquées.
2 > & amp; 1
est une construction shell POSIX. Voici une ventilation, jeton par jeton:
2
: " Erreur standard ". descripteur de fichier de sortie.
> & amp;
: Dupliquez un opérateur de descripteur de fichier de sortie (variante de Redirection de sortie , opérateur >
). Étant donné [x] & amp; [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 > & amp; 1
copie le descripteur de fichier 1
vers l'emplacement 2
, ainsi toute sortie écrite dans 2 ("erreur standard") de l'environnement d'exécution est identique au fichier initialement décrit par
1
("sortie standard").
Explication complémentaire:
Descripteur de fichier : "Un nombre entier non négatif unique par processus utilisé pour identifier un fichier ouvert aux fins de l'accès au fichier."
Sortie / erreur standard : reportez-vous à la remarque suivante dans le 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 numéros 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.
2 est l'erreur standard de la console.
1 est la sortie standard de la console.
Il s’agit de l’Unix standard et Windows suit également POSIX.
E.g. quand tu cours
perl test.pl 2>&1
l'erreur standard est redirigée vers la sortie standard afin que vous puissiez voir les deux sorties ensemble:
perl test.pl > debug.log 2>&1
Après l'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
La sortie standard passe ensuite à out.log et l'erreur type à err.log.
Je vous suggère d'essayer de les comprendre.
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 pagination pour toutes les sorties. Certains programmes, tels que l’impression d’informations d’utilisation sur 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; " & amp; 1 " pointe simplement tout ce qui est envoyé à stderr, à stdout à la place.
Je vous recommande également de lire ce message sur la redirection des erreurs , où ceci le sujet est traité en détail.
Du point de vue du programmeur, cela signifie précisément ceci:
dup2(1, 2);
Voir la page de manuel .
Comprendre que 2 > & amp; 1
est une copie explique également pourquoi ...
command >file 2>&1
... n'est pas la même chose que ...
command 2>&1 >file
Le premier enverra les deux flux dans le fichier
, tandis que le second enverra les erreurs dans stdout
et la sortie ordinaire dans le fichier
.
Mon mnémonique personnelle pour l'opérateur 2 > & amp; 1
est la suivante:
- Pensez que
& amp;
signifie'et'
ou'add'
(le caractère est un ampère - et , n'est-ce pas?) - Cela devient donc: 'redirigez
2
(stderr) vers où1
(stdout) est / est actuellement et ajoutez les deux les flux .
Le même mnémonique fonctionne pour l'autre redirection fréquemment utilisée, 1 > & amp; 2
:
- Pensez à
& amp;
qui signifieet
ouadd
... (vous avez une idée de l'esperluette, oui?) - Cela devient donc: 'redirigez
1
(stdout) vers où2
(stderr) est déjà / est actuellement et ajoutez les deux les flux .
Et souvenez-vous toujours: vous devez lire les chaînes de redirections "de la fin", de droite à gauche ( pas de gauche à droite).
Sous réserve que / foo
n'existe pas sur votre système et que / tmp
ne & & 8238;
$ ls -l /tmp /foo
imprimera le contenu de / tmp
et imprimera 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
imprimera le contenu de / tmp
et enverra 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
Cela revient à transmettre l'erreur au stdout 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 suit:
2>&1
Une erreur type est envoyée au terminal.
Entrée de redirection
La redirection d’entrée provoque le fichier dont le nom résultats de l'expansion du mot à ouvrir pour la lecture au dossier descripteur n, ou l’entrée standard (descripteur de fichier 0) si n est non spécifié.
Le format général de redirection des entrées est le suivant:
[n]<word
Redirection de la sortie
La redirection de la sortie provoque le fichier dont nom résulte de l'extension du mot à ouvrir pour écrire sur 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éé. si ça existe-t-il est tronqué à la taille zéro.
Le format général de redirection de la sortie est le suivant:
[n]>word
Descripteurs de fichiers en mouvement
L'opérateur de redirection,
[n]<&digit-
déplace le chiffre du descripteur de fichier vers le descripteur de fichier n, ou 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 sortie standard (descripteur de fichier 1) si n n'est pas spécifié.
Réf.:
man bash
Saisissez / ^ REDIRECT
pour accéder à la section redirection
et en savoir plus ...
Une version en ligne est disponible: 3.6 Redirections
PS:
Souvent, man
était l'outil puissant pour apprendre Linux.
0 pour l'entrée, 1 pour stdout et 2 pour stderr.
Un conseil :
somecmd > 1.txt 2 > & amp; 1
est correct, alors que somecmd 2 > & amp; 1> gt; 1.txt
est totalement faux sans effet!