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?
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
.
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.
Certaines particularités syntaxiques à ce sujet peuvent avoir des comportements importants. Il existe quelques exemples concernant les redirections, STDERR
, STDOUT
et les arguments ordering.
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.
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
_
Où 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.
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
_
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
_
_$ 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/
_
Vous pouvez lire le manuel en tapant:
_man -Len -Pless\ +/^REDIRECTION bash
_
dans une console bash ;-)
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:
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:
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> & 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 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:
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:
Bash voit maintenant la deuxième redirection, >file
, et redirige stdout vers 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 &> fichier
est exactement le même que:
$ commande> & file
Les chiffres renvoient aux descripteurs de fichier (fd).
stdin
stdout
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.
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.
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.
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.
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
"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.
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
.
À 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
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:
&
comme signifiant 'and'
ou 'add'
(le caractère est un ampère - et , n'est-ce pas?)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
:
&
signifiant and
ou add
... (vous avez une idée de l'esperluette, oui?)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).
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.
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é.
man bash
Tapez /^REDIRECT
pour localiser la section redirection
et en savoir plus ...
Une version en ligne est ici: .6 Redirections
La plupart du temps, man
était le puissant outil pour apprendre Linux.
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!