Je suis en train de lire sur la redirection des données vers /dev/null
et j'ai donc essayé un test simple:
ping a.b.c # which results in an address not found
Si j'essaye ceci:
ping a.b.c > /dev/null # prints the same error message as the one above
Cependant, si je fais ceci:
ping a.b.c > /dev/null 2>&1 # The error message is gone
Cette dernière solution est la solution souhaitée, mais que se passe-t-il avec ce 2>&1
? Mes recherches jusqu'à présent suggèrent que 2
représente stderr
et 1
représente stdout
. Donc, si je le lis de cette façon, on dirait que je crée un fichier stderr
et que je le redirige stdout
?
Si tel est le cas, que fait le &
dans cette commande?
Vous avez raison, 2
est STDERR
, 1
est STDOUT
. Lorsque vous faites 2>&1
vous dites: "affichez dans STDOUT
(1
) les éléments qui iraient dans STDERR
(2
)". Et avant cela, vous avez dit que votre STDOUT
irait à /dev/null
. Par conséquent, rien n'est vu. Dans les exemples 1 et 2, vous obtenez le message de sortie car il est imprimé sur STDERR
, car une redirection normale redirige uniquement STDOUT
.
Et lorsque vous effectuez la redirection, vous ne créez pas une STDERR
, les processus ont toujours une STDERR
et une STDOUT
lorsqu’ils sont créés.
Considérez le code suivant qui affiche le mot "stdout" sur stdout et le mot "stderror" sur stderror.
$ (echo "stdout"; echo "stderror" >&2)
stdout
stderror
Notez que l'opérateur '&' indique à bash que 2 est un descripteur de fichier (qui pointe vers le stderr) et non un nom de fichier. Si nous omettions le '&', cette commande afficherait stdout
sur stdout, créerait un fichier nommé "2" et y écrirait stderror
.
En testant le code ci-dessus, vous pouvez voir par vous-même exactement comment fonctionnent les opérateurs de redirection. Par exemple, en changeant quel fichier, lequel des deux descripteurs 1,2, est redirigé vers /dev/null
, les deux lignes de code suivantes suppriment tout ce qui se trouve sur la sortie standard et tout ce qui provient respectivement de stderror (ce qui reste).
$ (echo "stdout"; echo "stderror" >&2) 1>/dev/null
stderror
$ (echo "stdout"; echo "stderror" >&2) 2>/dev/null
stdout
Maintenant, nous abordons le noeud de la question (en substituant mon exemple au vôtre), pourquoi
(echo "stdout"; echo "stderror" >&2) >/dev/null 2>&1
produire aucune sortie? Pour vraiment comprendre cela, je vous recommande fortement de lire cette page Web sur les tables de descripteurs de fichiers . En supposant que vous ayez fait cette lecture, nous pouvons procéder. Notez que Bash traite de gauche à droite; Ainsi, Bash voit d'abord >/dev/null
(qui est identique à 1>/dev/null
) et définit le descripteur de fichier 1 sur/dev/null au lieu de la sortie standard. Ceci fait, Bash se déplace alors vers la droite et voit 2>&1
. Ceci définit le descripteur de fichier 2 pour qu'il pointe vers le même fichier que le descripteur de fichier 1 (et non pour le descripteur de fichier 1 lui-même !!!! (voir cette ressource sur les pointeurs pour plus d'informations). le descripteur de fichier 1 pointe sur/dev/null et le descripteur de fichier 2 pointe sur le même fichier que le descripteur de fichier 1, le descripteur de fichier 2 pointe désormais également sur/dev/null, de sorte que les deux descripteurs de fichier pointent sur/dev/null; pourquoi aucune sortie n'est rendue.
Pour tester si vous comprenez vraiment le concept, essayez de deviner le résultat lorsque nous inversons l'ordre de redirection:
(echo "stdout"; echo "stderror" >&2) 2>&1 >/dev/null
stderror
Le raisonnement est le suivant: en évaluant de gauche à droite, Bash voit 2> & 1, et définit ainsi le descripteur de fichier 2 de manière à pointer au même endroit que le descripteur de fichier 1, c’est-à-dire stdout. Il définit ensuite le descripteur de fichier 1 (rappelez-vous que>/dev/null = 1>/dev/null) pour qu'il pointe vers>/dev/null, supprimant ainsi tout ce qui serait normalement envoyé à la sortie standard. Ainsi, il ne nous reste plus que ce qui n’a pas été envoyé à stdout dans le sous-shell (le code entre parenthèses) - c’est-à-dire "stderror". La chose intéressante à noter est que même si 1 est juste un pointeur sur la sortie standard, la redirection du pointeur 2 vers 1 via 2>&1
ne forme PAS une chaîne de pointeurs 2 -> 1 -> stdout. Si tel était le cas, le code 2>&1 >/dev/null
donnerait à la chaîne de pointeurs 2 -> 1 ->/dev/null le résultat de la redirection de 1 vers/dev/null, et le code ne générerait rien, contrairement à ce que nous avons vu précédemment. .
Enfin, je noterais qu’il existe un moyen plus simple de procéder:
Dans la section 3.6.4 ici , nous voyons que nous pouvons utiliser l'opérateur &>
pour rediriger stdout et stderr. Ainsi, pour rediriger les sorties stderr et stdout de n'importe quelle commande vers \dev\null
(ce qui supprime la sortie), il suffit de taper $ command &> /dev/null
ou, dans le cas de mon exemple:
$ (echo "stdout"; echo "stderror" >&2) &>/dev/null
Points clés:
2>&1 >/dev/null
est! = >/dev/null 2>&1
. L'un génère une sortie et l'autre pas!Enfin, jetez un coup d’œil à ces excellentes ressources:
Documentation Bash sur la redirection , Explication des tables de descripteur de fichier , Introduction aux pointeurs