Ordre des redirections des sorties standards

bonjour ,

les 2 documents cités sont :
1- Introduction à la programmation en Bash en page 51
2 - Utiliser le pipe sur stderr - Linux Attitude au § " le niveau " vers la fin

  • doc1 en page 51 :
    Attention :
    Les redirections étant traitées de gauche à droite, l’ordre des redirections est important.

  • doc2 :
    Une dernière chose sur les redirections en bash, elles sont évaluées de droite à gauche.

Je vais me servir de l’exemple donné en page 51 par doc1 et à condition que j’interprète correctement :
La syntaxe &> fichier est équivalente à la syntaxe > fichier 2>&1
en prenant l’ordre (D → G ) de doc2 je pense que c’est correct et le fichier cible devrait enregistrer :

  • soit une ligne correspondant à stdout ou stderr
  • soit possiblement 2 lignes si ces sorties ne s’excluent pas mutuellement ( ce que je ne sais pas )

Si je prends la direction inverse le fichier enregistre stdout mais pas stderr à moins qu’il y ait un retour en arrière à partir de 2>&1 . Ça me semble un peu compliqué .

Comme les auteurs sont certainement des gens qui savent de quoi ils parlent il doit y avoir une explication .

ps : l’auteur de doc1 à qui j’ai soumis cette apparente contradiction vient de me répondre et me renvoie à Redirections (Bash Reference Manual) .

soit :

Note that the order of redirections is significant. For example, the command

ls > dirlist 2>&1

directs both standard output (file descriptor 1) and standard error (file descriptor 2) to the file dirlist, while the command

ls 2>&1 > dirlist

directs only the standard output to file dirlist, because the standard error was made a copy of the standard output before the standard output was redirected to dirlist.

ce qui me semble favoriser le sens (D–>G) mais bon ça n’est que mon interprétation .

Ben, c’est simple à tester.
Si tu fais

ls -l >&2 2> ./test

le retour de ls s’affiche dans la sortie et le fichier est vide alors que si tu fais

ls -l 2> ./test >&2

la sortie est vide et le fichier contient la sortie de ls.
Les redirections sont donc évaluées de droite à gauche.

ok mais comme je n’ai aucune connaissance particulière sur le sujet et au vu de toutes les âneries que j’ai pu écrire je ne m’avancerai certainement pas en terre inconnue . Donc , pour une fois , je n’ai pas tiré de conclusion erronée ? . On progresse .

merci pour la réponse .

En fait, c’est bien ce qui est écrit dans le document : l’ordre d’imbrication des redirections se fait de droite à gauche <=> de la fin de la ligne de commandes vers le début de la ligne de commandes.

Si je veux envoyer dans le fichier nommé mesSorties les flux stderr et stdout,
je vais d’abord rediriger flux stderr vers le flux stdout en utilisant la syntaxe : 2>&1
et ensuite, je vais rediriger le flux stdout vers le fichier nommé mesSorties.

Comme les redirections sont interprétées de droite à gauche, si je veux d’abord rediriger flux stderr vers le flux stdout en utilisant la syntaxe : 2>&1 il me faudra placer cette redirection à la fin de ma ligne de commandes.

Et comme je veux que la sortie (<=> les deux flux rassemblés par cette redirection qui sera interprétée en premier puisque c’est celle qui est à la fin de la ligne de commandes) soit redirigée vers le fichier mesSorties.txt, je vais finalement faire :

ls fichierÀlister > mesSorties.txt 2>&1

Ce qui donnera :

  • dans le cas d’un nom de fichier qui n’existerait pas :
    Le message d’erreur de la commande ls sera retourné par son flux stderr
    et comme ce flux stderr avait été préalablement redirigé vers le flux stdout finalement le flux stdout résultant sera redirigé vers le fichier nommé mesSorties.txt
michel@deb115:~$ ls fichierPasExistant > mesSorties.txt 2>&1
michel@deb115:~$ cat mesSorties.txt 
ls: impossible d'accéder à 'fichierPasExistant': Aucun fichier ou dossier de ce type
michel@deb115:~$ 

  • Et dans le cas d’un fichier existant :
    il n’y aura pas de message d’erreur, mais le flux stdout de la commande ls sera toujours redirigé vers le fichier nommé mesSorties.txt
michel@deb115:~$ ls ~/.bashrc > mesSorties.txt 2>&1
michel@deb115:~$ cat mesSorties.txt 
/home/michel/.bashrc
michel@deb115:~$ 

Comme pour certains shampoings,
la ligne de commandes :

ls fichierÀlister > mesSorties.txt 2>&1

est équivalente à :

ls fichierÀlister &> mesSorties.txt

je mets la réponse de l’auteur du cours IUT-Rodez :

A l’url :
Redirections (Bash Reference Manual)
vous trouverez la phrase :
« Redirections are processed in the order they appear, from left to right. »

et effectivement on trouve bien cette phrase dans le manuel de référence . On dirait qu’on parle de deux choses différentes , mais quoi ? Le manuel de référence cité plus haut ne va pas raconter d’âneries quand même ! Ou alors ce serait une coquille reprise par l’auteur du cours ? Hum…

sous toutes réserves je vais tenter une explication pour concilier ces deux points de vue ( axiome = le manuel ne peut pas se tromper ) surtout à cause de ceci que je viens de lire :

Note, however, that output isn’t actually sent until all redirections are in place, and that any redirection-target output files are created or truncated before command execution begins …

  • la lecture s’effectue de gauche à droite comme le dit le manuel mais aucune action finale n’intervient tant que toutes les redirections ne sont pas prises en compte
  • donc tant que la redirection 2>&1 située en fin de la ligne de commande n’est pas lue et prise en compte rien n’est définitif et donc tout se passe comme si le départ se situait à la fin de la ligne de commande qui en déclenche l’exécution ( sans compter la création éventuelle de fichiers cibles )

C’est assez rudimentaire car ce qui se passe réellement m’a l’air bien plus complexe et reste hors de ma portée .

Pour plus de détails voir ici ( pas très loin du début de page ) : bash - Shell redirection i/o order - Stack Overflow

J’avoue qu’avec la fatigue, j’ai sans doute mal interprété la lecture du manuel de bash et du document créé par Eric Sanchis.

Quoiqu’il en soit, le manuel de l’interpréteur de commande bash est LA référence fiable
et il est évident que Mr Eric Sanchis est beaucoup plus compétent que moi.

la solution est peut-être bien ci-dessous (lien donné plus haut que j’ai relu ) et alors tout se passe de gauche à droite :

Redirections are:

  • processed from left to right .

  • interpreted iteratively :

  • Note, however, that output isn’t actually sent until all redirections are in place, and that any redirection-target output files are created or truncated before command execution begins (this is the reason why you can’t read from and redirect output to the same file with a single command).

Applied to the example from the question:

  • >file 2>&1 :
  • >file first redirects stdout (file descriptor 1 , implied by not prefixing > with a file >descriptor number) to output file file
  • 2>&1 then redirects stderr ( 2 ) to the already redirected stdout ( 1 ).
  • The net effect is that both original streams end up in file .

Je ne sais pas ce que tu veux dire, mais si tu lances

ls -l /non/existant/directory 2>./test 2>&1

le fichier ./test sera vide et la sortie d’erreur standard s’affichera à l’écran.
Une fois que bash a connecté la sortie d’erreur dans la sortie standard (2>&1), tu n’auras plus rien qui sortira de la sortie d’erreur standard.

(note pour moi-même, faire des tests avec bash quand la question concerne bash)

onpeut même généraliser cette constatation dans le cas où les redirections impliquent le même descripteur :

mm@Xfce:~$ ls -l ned 2>t1 2>&1 
ls: impossible d'accéder à 'ned': Aucun fichier ou dossier de ce type
mm@Xfce:~$ cat t1
mm@Xfce:~$ ls -l ned 2>t1 2>&1 2>t2
mm@Xfce:~$ cat t1
mm@Xfce:~$ cat t2
ls: impossible d'accéder à 'ned': Aucun fichier ou dossier de ce type
mm@Xfce:~$ ls -l ned 2>t1 2>&1 2>t2 2>&1
ls: impossible d'accéder à 'ned': Aucun fichier ou dossier de ce type
mm@Xfce:~$ cat t1
mm@Xfce:~$ cat t2

on voit alors que seule la dernière redirection est prise en compte .

comment expliquer ce comportement ? À moins de savoir comment s’effectue l’exécution pas à pas de cette commande je ne vois pas comment on pourrait le faire . Et là je suis évidemment aux abonnés absents , mais ça m’intéresserait de connaître la réponse ; par simple curiosité . Mais sûr que dans ton exemple tout se passe comme si on effectuait les opérations en partant de la droite .

ps :
et puis en restant sur le sujet originel on peut tenter d’expliquer l’exécution de la commande
>fich 2>&1 exécutée de gauche à droite :

  • 1 → fich suivi de 2 -->1 et comme 1 pointe toujours vers fich alors 2 est dirigée vers fich
  • dans fich on a donc bien les sorties de stdout et stderr

logique ou pas ?

Voici comment je vois les choses.
D’abord utiliser une commande simple qui produit d’une manière fiable à la fois les flux de sortie normale (stdout) et flux d’erreur (stderr).
Si aucune redirection tout s’affiche à l’écran :

1& fp2@debpacha:/tmp $ id  root 1000 inconnu 0
uid=0(root) gid=0(root) groupes=0(root)
uid=1000(fp2) gid=1000(fp2) groupes=1000(fp2),4(adm),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev),114(bluetooth),115(lpadmin),119(scanner),126(fuse)
id: « inconnu » : utilisateur inexistant
uid=0(root) gid=0(root) groupes=0(root)
1& fp2@debpacha:/tmp 1 $

Nous pouvons rediriger explicitement les flux 1 (stdout) et 2 (stderr) chacun dans son fichier

id  root 1000 inconnu 0 1> id.txt 2> id.err

ou bien ne détourner qu’un seul des flux, typiquement un truc du genre 2> /dev/null
Remarque on peut aussi la redirection en mode append avec >> et/ou 2>>.

Maintenant, si nous voulons combiner les deux flux et rediriger le tout dans un seul fichier, on commence par rediriger un des flux (le 1 par exemple) dans un fichier, puis on redirige l’autre (le 2) vers le premier On ne peut pas écrire 2>1 car ce serait vers un fichier nommé ‹ 1 ›.

1& fp2@debpacha:/tmp $ id  root 1000 inconnu 0 >> id.txt 2>&1
1& fp2@debpacha:/tmp 1 $ cat id.txt
uid=0(root) gid=0(root) groupes=0(root)
uid=1000(fp2) gid=1000(fp2) groupes=1000(fp2),4(adm),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev),114(bluetooth),115(lpadmin),119(scanner),126(fuse)
uid=0(root) gid=0(root) groupes=0(root)
uid=0(root) gid=0(root) groupes=0(root)
uid=1000(fp2) gid=1000(fp2) groupes=1000(fp2),4(adm),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev),114(bluetooth),115(lpadmin),119(scanner),126(fuse)
id: « inconnu » : utilisateur inexistant
uid=0(root) gid=0(root) groupes=0(root)
1& fp2@debpacha:/tmp $

C’est très logique, à part cette histoire de syntaxe ‹ &1 › pour désigner un descripteur d’un flux existant.

Bravo !
Reste à savoir si ce super raccourci est un bashisme ou si c’est standard En tout cas, merci.

Cordialement,
Regards,
Mit freundlichen Grüßen,
مع تحياتي الخالصة


F. Petitjean
Ingénieur civil du Génie Maritime.

« On ne perd pas son temps en aiguisant ses outils. »
Proverbe français

« Moi, lorsque je n’ai rien à dire, je veux qu’on le sache. » (R. Devos)

en revenant sur ce point et à condition que la source ci-dessous soit crédible pas besoin de D–>G pour l’interprétation , le G–> D marche très bien :

lu ici : bash - Two redirection operators in one command - Stack Overflow

-ls >file1 >file2

Why does the output go to file2 instead of file1?

bash only allows one redirection per file descriptor. If multiple redirections are provided, like in your example, they are processed from left to right, with the last one being the only one that takes effect.

Some shells (like zsh ) have an option to allow multiple redirections. In bash , you can simulate this with a series of calls to tee

Je ne suis pas une source crédible, je propose juste un protocole d’expérimentation reproductible et je donne mes résultats et mes interprétations de ces résultats.
J’invite les gens à reproduire ces expériences afin de vérifier que le comportement attendu est bien le bon.

Oui, on peut lire de droite à gauche, ou lire de gauche à droite en lisant à l’envers.

je cherchais juste une explication qui :

  • pouvait s’accorder avec ce que ton exemple montre
  • tout en restant en accord avec ce que dit le manuel de référence

Reste quand même le doc2 que je mentionnais au début et qui a l’air d’être sûr de lui . Pour le réfuter un seul contre-exemple suffirait . Je laisse ça à des gens compétents . Éventuellement .