Pourquoi rediriger la sortie vers 2> & 1 et 1> & 2?

36

J'ai rencontré plusieurs commandes qui utilisent 2>&1et 1>&2, mais je n'arrive pas à comprendre le but de l'utiliser et quand je devrais l'utiliser.

Ce que je comprends

Je sais que cela 1représente une sortie standard et 2une erreur standard. Je comprends que 2>&1combine la sortie de 2à 1et vice versa.

Ce que je n'obtiens pas

  1. Quand devrais-je l'utiliser?
  2. A quoi est-ce que ça sert?
PeanutsMonkey
la source

Réponses:

39

Parfois, vous souhaitez rediriger à la fois stdout et stderr vers le même emplacement, c'est quand >&est utilisé - il pointe un descripteur de fichier vers un autre.


Par exemple, si vous souhaitez écrire à la fois stdout et stderr dans le même fichier (que ce /dev/nullsoit ou output.txt), vous pouvez les rediriger séparément, avec

app 1>/dev/null 2>/dev/null

ou vous pouvez rediriger un descripteur de fichier vers le fichier, et l'autre descripteur de fichier dans le premier:

app 1>/dev/null 2>&1

app 2>/dev/null 1>&2

Dans le premier exemple, 2>&1pointe le descripteur de fichier # 2 vers l'endroit où # 1 pointe déjà. Le deuxième exemple obtient le même résultat, commençant simplement par stderr à la place.

Comme autre exemple, il y a des cas où stdout (descripteur de fichier # 1) pointe déjà vers l'emplacement souhaité, mais vous ne pouvez pas y faire référence par son nom (il peut être associé à un tuyau, une prise ou autre). Cela se produit souvent lorsque vous utilisez l'expansion de processus (les opérateurs ` `ou $( )), qui ne capture normalement que stdout, mais vous souhaiterez peut-être y inclure stderr. Dans ce cas, vous utiliseriez également >&pour pointer stderr vers stdout:

out=$(app 2>&1)

Un autre exemple courant est un pageur, ou grepun utilitaire similaire, car le canal |ne fonctionne normalement que sur stdout, vous redirigez stderr vers stdout avant d'utiliser le canal:

app 2>&1 | grep hello

Comment savoir lequel 2>&1ou qui 1>&2est correct? Le descripteur de fichier déjà configuré va à droite de >&et le descripteur de fichier que vous souhaitez rediriger va à gauche. ( 2>&1signifie "pointer le descripteur de fichier # 2 vers le descripteur de fichier # 1".)


Certains shells ont des raccourcis pour les redirections courantes; voici des exemples de Bash:

  • 1> peut être raccourci à seulement >

  • 1>foo 2>&1à >&fooou&>foo

  • 2>&1 | program à |& program

Grawity
la source
Je ne savais pas que faire app 1>/dev/null 2>&1signifierait que 2> & 1 pointerait vers le fichier vers lequel 1 était déjà en train de rediriger. Je suppose que je pourrais tout aussi facilement le faire app > /dev/null &>?
PeanutsMonkey
J'ai du mal à comprendre the already set up fd goes to the right of >&, and the fd you want to redirect goes to the left. Que voulez-vous dire par le descripteur de fichier déjà configuré? Que signifie le droit de?
PeanutsMonkey
Désolé, sauf si vous aviez l'intention de m'enseigner les directions, je ne suis pas conforme à la déclaration que vous avez faite, comme indiqué précédemment.
PeanutsMonkey
1
Prenez chaque descripteur de fichier rediriger un à la fois, de gauche à droite, et appliquez ces règles dans cet ordre. Si vous dirigez d' abord stdout vers un fichier, puis redirigez stderr vers l'endroit où stdout nous pointe maintenant, alors stderr et stdout iront dans le même fichier. Si vous échangiez ces deux redirections, vous obtiendriez des résultats différents (redirigez stderr vers où stdout va maintenant , puis déplacez stdout pour pointer vers un autre fichier, tandis que stderr continue là où il a été pointé).
Jason
2

Une situation où vous en avez besoin est lorsque vous souhaitez afficher la stracesortie dans un pager. straceimprime sa sortie à l' erreur standard et les tuyaux connectent généralement la sortie standard à l'entrée standard, vous devez donc utiliser la redirection:

strace -p $pid 2>&1 | less
jpalecek
la source
Qu'entendez-vous par pipes generally connect standard output to standard input?
PeanutsMonkey
2
Je veux dire que pipe ( |) prend la sortie standard de la première commande et la connecte à l'entrée standard de la deuxième commande.
jpalecek
2

Parfois, vous souhaitez rediriger à la fois stdout( 1) et stderr( 2) vers le même emplacement ( /dev/null, par exemple). Un moyen d'y parvenir serait:

$ program 1>/dev/null 2>/dev/null

Mais la plupart des gens raccourcissent cela en redirigeant stderrvers stdoutavec 2>&1:

$ program 1>/dev/null 2>&1

Une version encore plus courte est:

$ program >&- 2>&-
Zaz
la source
1

2: C'est lorsque vous aurez une sortie provenant à la fois d'une erreur standard et d'une sortie standard, et que vous souhaiterez les composer en une seule chaîne.

1: Lorsque vous souhaitez manipuler la sortie de l'erreur standard et de la sortie standard.

soandos
la source
Qu'entendez-vous par manipuler? Ma compréhension est que tout ce qui est redirigé vers >2est envoyé à / dev / null. Ou ai-je complètement mal compris?
PeanutsMonkey
Ce n'est pas correct. Par manipuler, je veux dire le diriger vers grep ou quelque chose de similaire. Voir ici pour un exemple.
soandos
0

Je l'utilise pour démarrer un travail détaché:

someProgram 2>&1 >& my.log &

alors je peux me déconnecter, et certains programmes seront toujours en cours d'exécution. La fonctionnalité est fournie par GNU Screen, tmux et certains autres programmes - mais ici, elle est réalisée sans aucune dépendance externe.

Adobe
la source
1
Cela ne fonctionne que tant qu'aucun SIGHUP n'est envoyé au programme. Mieux utiliser nohupou disowndans de tels cas.
slhck
@slhck: ok. Mais si je ne veux pas envoyer SIGHUP au programme - personne ne le fera, non?
Adobe
Non, le terminal de contrôle avertira les processus d'une déconnexion avec SIGHUP. En pratique, si vous exécutez un shell distant via SSH et quittez, votre processus mourra également, par exemple.
slhck
@slhck: Cela ne peut pas être vrai: je l'utilise depuis quelques années - je me déconnecte de ssh, et le processus est toujours en cours.
Adobe
Je vais devoir examiner cela plus en détail, mais le simple fait de mettre des programmes en arrière-plan n'a pas fonctionné pour moi dans tous les cas, et cela ne fonctionne certainement pas sur ma machine locale. Zsh et Bash se comportent différemment ici aussi, semble-t-il.
slhck
0

Imaginez qu'il existe un répertoire nommé trycontenant ces trois fichiers:file file1 and file2.

Exécutez maintenant cette commande:

cat file file1 file2 file3

Les trois premiers fichiers s'ouvrent mais catgénèrent une erreur lors de l'ouverture du quatrième car il n'existe pas.

Maintenant, lancez:

cat file file1 file2 file3 1>outfile 2>&1

Vous ne verrez aucune sortie à l'écran: Tout d' abord 1>outfileredirigera la sortie de la commande outfilepuis il redirigera ( 2>&1) l'erreur jeté en essayant d'ouvrir file3à outfile.

1>&2 fonctionne de manière similaire et redirige le flux d'erreurs vers la sortie standard.

J'espère que cela t'aides!

Faiz
la source
0

Scénario alternatif: les commandes du terminal affichent la sortie dans un autre terminal

Utilisez la ttycommande dans chaque terminal pour les identifier:

$ tty
/dev/pts/0

$ tty
/dev/pts/1

En supposant que ces ATS, pour rediriger la sortie standard du premier vers le second, exécutez ceci dans le premier terminal:

exec 1>/dev/pts/1

Remarque: Maintenant, chaque sortie de commande s'affiche sur pts / 1

Pour restaurer le comportement par défaut stdout de pts / 0:

exec 1>/dev/pts/0

Voir cette vidéo pour une démonstration.

Vitalie Ghelbert
la source
0

Le cas de la redirection de stderr vers stdout a déjà été traité ici (par exemple, utilisez-le pour filtrer (grep) les messages d'erreur).

L'autre cas redirige stdout vers stderr. Une utilisation courante (au moins pour moi) consiste à envoyer des avertissements / messages d'erreur imprimés avec "echo" (dans mes scripts shells) au stderr (afin qu'ils puissent attirer plus facilement l'attention de l'utilisateur).

Par exemple,

echo "file \"${file\" does not exist..." 1>&2
umläute
la source