- stderr (sortie d’erreur standard) et stdout (sortie standard) sont réunis en un seul flux à l’aide d’une syntaxe de redirection
- Le chiffre 1 désigne stdout, 2 désigne stderr, et
& sert à indiquer une référence à un descripteur de fichier
2>&1 signifie « envoyer stderr vers la destination actuelle de stdout », et le résultat dépend de l’ordre des redirections
- Par exemple,
command >file 2>&1 envoie les deux flux dans le fichier, tandis que command 2>&1 >file laisse stderr sur la console
- Il s’agit d’une syntaxe de redirection essentielle, fréquemment utilisée dans Bash et les shells POSIX pour fusionner les sorties, enregistrer des logs et gérer des pipelines
Descripteurs de fichier et notions de base
- 0, 1, 2 désignent respectivement stdin, stdout, stderr
- Ils sont définis dans
/usr/include/unistd.h
#define STDIN_FILENO 0, #define STDOUT_FILENO 1, #define STDERR_FILENO 2
> indique une redirection de sortie, `` réécrit le fichier, et >> ajoute à la fin du fichier
- Le symbole
& indique qu’on référence un descripteur et non un nom de fichier
- Ainsi,
2>1 redirige vers un fichier nommé 1, tandis que 2>&1 duplique stderr vers stdout
Principe de fonctionnement de 2>&1
2> signifie qu’il faut rediriger stderr, et &1 référence le descripteur de fichier de stdout
- En conséquence, stderr est envoyé vers la même destination que stdout
- Exemples :
ls -ld /tmp /tnt >/dev/null 2>&1 → les deux sorties sont ignorées dans /dev/null
ls -ld /tmp /tnt 2>&1 >/dev/null → seul stderr reste affiché sur la console
- Les redirections sont traitées de gauche à droite, donc un ordre différent produit un résultat différent
Pourquoi l’ordre des redirections est important
command >file 2>&1
- stdout est d’abord envoyé dans le fichier, puis stderr est dupliqué vers stdout → les deux flux vont dans le fichier
command 2>&1 >file
- stderr est d’abord dupliqué vers le stdout courant (la console), puis seul stdout est redirigé vers le fichier → stderr continue de s’afficher sur la console
- Bash traite les redirections dans l’ordre, il faut donc faire attention à la séquence lors de l’écriture des commandes
Différents exemples de redirection
echo test >file.txt → redirige stdout vers le fichier
echo test 2>file.txt → redirige stderr vers le fichier
echo test 1>&2 → redirige stdout vers stderr
command &>file ou command >&file → redirige stdout et stderr vers le fichier (forme abrégée Bash)
command 2>&1 | tee -a file.txt → envoie les deux flux à la fois vers le fichier et le terminal
Usages avancés et fonctionnalités depuis Bash 4.0
- Depuis Bash 4.0, il est possible de séparer les sorties à l’aide de la substitution de processus
ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
- stdout et stderr sont envoyés chacun vers un filtre différent
|& est une forme abrégée de 2>&1 |, qui transmet les deux flux fusionnés dans un pipeline
- L’option
set -o noclobber empêche l’écrasement d’un fichier existant, avec possibilité d’exception via >|
Exemples d’usage en pratique
g++ main.cpp 2>&1 | head → permet de ne voir que le début de la sortie, y compris les erreurs de compilation
perl test.pl > debug.log 2>&1 → enregistre toute la sortie et les erreurs dans un fichier de log
foo 2>&1 | grep ERROR → recherche la chaîne ERROR à la fois dans stdout et stderr
docker logs container 2>&1 | grep "some log" → envoie l’ensemble des logs dans le pipeline
À retenir
2>&1 est une syntaxe POSIX standard qui duplique stderr vers stdout
- L’ordre des redirections détermine le résultat, il faut donc être vigilant lors de l’écriture des commandes
- Dans Bash,
&> permet de traiter les deux flux en même temps, et cette syntaxe est indispensable dans de nombreux scripts d’automatisation pour la gestion des logs, le traitement par pipeline et la fusion des erreurs
1 commentaires
Avis sur Hacker News
Du point de vue de l’API des appels système Unix,
2>&1a le même sens quedup2(1, 2)Dans les shells Unix classiques, c’est tout ce qu’il y a à savoir, mais dans les shells modernes, un bookkeeping interne s’ajoute pour suivre l’état
les redirections sont exécutées de gauche à droite de façon séquentielle, et l’opérateur pipe fonctionne comme une combinaison de fork et de dup
En revanche, même si comprendre
dup2(2, 1)comme2<1semble intuitif, c’est une interprétation erronée du point de vue sémantique des E/SIl était entre la page man7 de dup2 et la page Arch Linux de dup2
C’est étonnant de voir que des bots lisent ça
Il y a trop de sucre syntaxique qui masque les mécanismes internes
Contrairement à des langages comme Lisp, qui étendent une structure simple avec des macros, le shell a des règles syntaxiques complexes et peu intuitives
Au fond, ce genre de plainte ressemble à un conflit d’ego entre programmeurs et administrateurs système
En revanche, si le descripteur n’a pas été ouvert à l’avance, on obtient une erreur « Bad file descriptor »
Les redirections utilisent dup avant exec, et les pipes utilisent deux fork ainsi que l’appel système
pipeLe manuel de BASH est vraiment très bien fait, donc mieux vaut consulter la documentation officielle
Mais dans les langages modernes ou hors de l’univers Unix, cette intuition se perd
Au final, lire directement la documentation officielle (RTFM) reste le plus sûr
Manuel Bash Redirections
La plupart trouvent leurs réponses via Google, et il faut que ce type de questions s’accumule pour que des résultats existent
Les différents points de vue sur Stack Overflow sont souvent plus utiles aux débutants
Un utilisateur ordinaire a du mal à trouver l’information voulue
Une réponse sur Stack Overflow exprimait exactement ce que je pensais, donc je la cite telle quelle
Si c’est
2>&1et non&2>&1, c’est parce que&ne signifie un descripteur de fichier que dans le contexte d’une redirectionIl est intéressant de voir que PowerShell a conservé la même syntaxe
Lien vers la documentation officielle
L’ordre de
2>&1 > filey est l’inverse d’Unix, donc on n’obtient pas le résultat attenduAvant la version 7.4, il y avait aussi un problème de corruption des flux d’octets
Documentation associée
>indique quel descripteur de fichier rediriger>fooest équivalent à1>fooÉcrire
2>>&1créerait un fichier nommé1, donc cela n’a pas de sens>signifie stdout,2>stderr, et&1stdoutfile1>file2n’est pas symétrique non plus/dev/stderr>/dev/stdoutest une correspondance plus directeL’explication de Claude était la plus facile à comprendre
2>&1signifie « envoyer la sortie d’erreur au même endroit que la sortie standard »2désigne la sortie d’erreur,>signifie « envoyer vers », et&1signifie « là où stdout pointe actuellement »2désigne le descripteur de fichier 2,>une affectation, et&1le descripteur de fichier 1Il est plus efficace de cliquer directement sur le lien que de passer par un LLM
L’époque de Stack Overflow, où l’on posait des questions à des humains, me manque
Mais il est désormais difficile de revenir à cette époque
Mais même à l’époque, il y avait beaucoup de gatekeeping et d’ambiance cynique
La collaboration centrée sur l’humain n’a pas toujours quelque chose de romantique
Elles allaient droit au but sans introduction inutile
Avec un humain viennent des charges sociales comme la nécessité de lire l’ambiance, l’évaluation ou la rivalité
Un LLM, lui, donne une réponse neutre et polie sans ce poids
Le comportement du shell est dépendant du contexte, donc la signification de
&varie selon sa positionComme dans
IFS=\| read A B C <<< "first|second|third", où cela ne s’applique localement qu’à une seule ligneUn
&en fin de ligne signifie une exécution en arrière-plan, alors qu’au milieu il a un sens de redirectionCe genre de motif est difficile à assimiler, mais il faut finir par l’apprendre
Cela rappelle à quel point les systèmes que nous utilisons sont archaïques
Manipuler les descripteurs de fichiers par des nombres, c’est un peu comme donner directement des pointeurs à l’utilisateur
Un accès basé sur des noms serait préférable
&sert à indiquer qu’il ne s’agit pas d’un fichier mais d’un descripteur<était déjà pris pour la redirection d’entrée, donc impossible de le réutiliser2>/dev/stdoutressemble à2>&1, mais ce n’est pas exactement pareil/dev/stdoutest une approche plus familière et fondée sur des nomsUn script écrit il y a 15 ans fonctionne encore tel quel aujourd’hui
Les redirections sont une fonctionnalité vraiment fascinante
Par exemple, j’utilise souvent la substitution de processus dans des commandes comme
diff <(seq 1 20) <(seq 1 10)Ce serait bien plus puissant si l’on pouvait transmettre directement des fichiers, des flux ou des sockets à un processus
Si Bash pouvait ouvrir directement un socket et le passer à un autre programme, le sandboxing serait aussi plus simple
[^1]: Il existe bien
/dev/tcp, mais ses possibilités sont limitéesEn réalité, c’est implémenté avec un named pipe, donc sans possibilité de seek
C’est pourquoi Zsh a ajouté la syntaxe
=(command), qui utilise un fichier temporaireMoi, j’ai retenu
2>&1comme « 2 entre dans l’adresse de 1 »Comme article traitant en profondeur de
2>&1et des redirections, il y aUnderstanding Linux's File Descriptors: A Deep Dive Into '2>&1' and Redirection
Lien vers la discussion associée
Lien vers le livre