web-dev-qa-db-fra.com

Comment fonctionne cmd>/dev/null 2> & 1?

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?

11
hax0r_n_code

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.

12
msb

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:

  • Les descripteurs de fichier se comportent comme des pointeurs (bien que les descripteurs de fichier ne soient pas identiques aux pointeurs de fichier)
  • En redirigeant un descripteur de fichier "a" vers un descripteur de fichier "b" pointant vers le fichier "f", le descripteur de fichier "a" pointe au même endroit que le descripteur de fichier b - fichier "f". Il ne forme pas une chaîne de pointeurs a -> b -> f
  • En raison de ce qui précède, l'ordre compte, 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

0
Evan Rosica