OVH Cloud OVH Cloud

[Bash] Redirection de flux de sortie

2 réponses
Avatar
hugolino
Bonjour à tous

Pour améliorer les scripts que j'écris, je regarde comment sont fait
ceux qui sont sur le système...


Dans le script /etc/ppp/ip-up.d/fetchmail, il y a une ligne que je ne
comprends pas:
/etc/init.d/fetchmail awaken >/dev/null 2>&1 || /etc/init.d/fetchmail
start



Je sais que 'toto || tata' exécute 'toto' puis si 'toto' renvoie une
erreur (une valeur non nulle) exécute tata.

Je sais que 'toto' affiche les messages de sortie standard de 'toto'.

Si je ne veux que les messages de sortie stantard de 'toto' je fais
'toto 2> /dev/null' (ça supprime les messages de stderr).
Si je ne veux que les messages d'erreur, je fais 'toto 1> /dev/null'.
Si je ne veux rien voir, je fais 'toto &> /dev/null'

Mais quel peut être l'intéret de faire 'toto >/dev/null 2>&1' ?

'toto >/dev/null' ne laisse que la sortie d'erreur visible (c'est bien
sûr équivalent à 'toto 1>/dev/null')

Mais 'toto >/dev/null 2>&1' ne donne aucune sortie, puisque selon moi la
sortie de 'toto >/dev/null' est constituée des erreurs rencontrées par
toto, mais ne constitue pas une erreur en elle même puisque c'est ce
qu'on voulait. (Le stdout de 'toto >/dev/null' est constitué du stderr
de 'toto'). Donc le stderr de 'toto >/dev/null' est vide et renvoyer ce
2 sur le 1 supprime le stdout.

Est-ce que j'ai compris ?

Comment dans ce cas la ligne de script que j'ai vu peut elle marcher ?
Je me doute bien qu'elle doit marcher, mais comment...



En fait le programme 'toto' dont je parle est 'grep lulu *' sur mon
home, et j'ai eu des trucs très bizarres:

Si je fais 'grep lulu *' j'ai 92 lignes dont 32 messages d'erreur (car
j'ai 32 répertoires dans mon home) et ces 32 lignes d'erreur sont
mélangées au mileu des 60 autres car grep procède dans l'ordre
alphabetique. --> OK

1) Si je fais 'grep lulu * | wc -l' j'ai les 32 messages d'erreur *puis*
le nombre 60. --> Bizarre pourquoi wc ne compte t-il pas les 32 lignes
d'erreur qui doivent quand même faire partie de la sortie standard
puisque si je ne mets pas '|wc -l' j'ai 92 lignes ??

2) Si je me trompe et que je tape 'wx' au lieu de 'wc', j'ai le message
d'erreur de bash *avant* les 32 messages d'erreur. --> Bash évalue la
ligne commande avant de l'exécuter ?

3) Si je fais 'grep lulu * >/dev/null | wc -l', j'ai les 32 messages
d'erreur *précédés* du chiffre '0' --> On a l'impression qu'il a exécuté
le 'wc -l' avant que 'grep lulu * >/dev/null' soit exécuté ! --> Comment
peut-il savoir le résultat d'une commande qui n'est pas encore finie ?

4) Si je fais 'grep lulu * >/dev/null | wc | wc' , j'ai toujours mes 32
erreurs mais '1 3 24' apparait soit en première ligne, soit au milieu de
mes erreurs et 24 est le nombre de caractères de 'grep toto * >/dev/null|wc'
--> Pourquoi le résultat du dernier wc apparait il un peu au hasard ?
Les deux programmes s'exécute en même temps ? Je pensais que le dernier
'wc' attendait que ce qui précède soit fini.



Le message est un peu long, mais il m'a fallut moins de temps pour le
rédiger que pour faire mes tests ;)

Merci de m'avoir lu.

--
/(_M_)\ .------------------------------. /(_M_)\
| | ( POWERED BY Alain KRIVINE/LINUX ) | |
\/~V~\/ `------------------------------' \/~V~\/
-+- DB in Guide du linuxien pervers - "Mieux que la SLS : la LCR !"

2 réponses

Avatar
Thomas Nemeth
Le mer 07 jan 2004 à 05:18, Hugolino a tapoté :
|
| Bonjour à tous

Salut ?


| Dans le script /etc/ppp/ip-up.d/fetchmail, il y a une ligne que je ne
| comprends pas:
| /etc/init.d/fetchmail awaken >/dev/null 2>&1 || /etc/init.d/fetchmail
| start
|
| Je sais que 'toto || tata' exécute 'toto' puis si 'toto' renvoie une
| erreur (une valeur non nulle) exécute tata.

Oui.


| Je sais que 'toto' affiche les messages de sortie standard de 'toto'.

Heureusement :)


| Si je ne veux que les messages de sortie stantard de 'toto' je fais
| 'toto 2> /dev/null' (ça supprime les messages de stderr).

Oui.


| Si je ne veux que les messages d'erreur, je fais 'toto 1> /dev/null'.

Oui.


| Si je ne veux rien voir, je fais 'toto &> /dev/null'

Connais pas, mais pourquoi pas.


| Mais quel peut être l'intéret de faire 'toto >/dev/null 2>&1' ?

Envoie la sortie standard stdout vers /dev/null et redirige stderr
vers stdout (donc vers /dev/null aussi).


| Mais 'toto >/dev/null 2>&1' ne donne aucune sortie,

Oui, c'est le but.


| puisque selon moi la
| sortie de 'toto >/dev/null' est constituée des erreurs rencontrées par
| toto, mais ne constitue pas une erreur en elle même puisque c'est ce
| qu'on voulait. (Le stdout de 'toto >/dev/null' est constitué du stderr
| de 'toto'). Donc le stderr de 'toto >/dev/null' est vide et renvoyer ce
| 2 sur le 1 supprime le stdout.
|
| Est-ce que j'ai compris ?

Je ne sais pas : tes explications sont incompréhensibles :)

toto >/dev/null 2>&1
^^^^^^^^^^^ ^^^^_________________
redirige stdout vers /dev/null `- fait un dup() de stdout et
l'associe à stderr.


| Comment dans ce cas la ligne de script que j'ai vu peut elle marcher ?

Quel rapport ?


| Si je fais 'grep lulu *' j'ai 92 lignes dont 32 messages d'erreur (car
| j'ai 32 répertoires dans mon home) et ces 32 lignes d'erreur sont
| mélangées au mileu des 60 autres car grep procède dans l'ordre
| alphabetique. --> OK
|
| 1) Si je fais 'grep lulu * | wc -l' j'ai les 32 messages d'erreur *puis*
| le nombre 60. --> Bizarre pourquoi wc ne compte t-il pas les 32 lignes
| d'erreur qui doivent quand même faire partie de la sortie standard
| puisque si je ne mets pas '|wc -l' j'ai 92 lignes ??

Les 32 messages d'erreurs sont envoyés sur stderr et ton pipe ne
récupère que stdout.
grep lulu * 2>&1 | wc -l


| 2) Si je me trompe et que je tape 'wx' au lieu de 'wc', j'ai le message
| d'erreur de bash *avant* les 32 messages d'erreur. --> Bash évalue la
| ligne commande avant de l'exécuter ?

Oui.


| 3) Si je fais 'grep lulu * >/dev/null | wc -l', j'ai les 32 messages
| d'erreur *précédés* du chiffre '0' --> On a l'impression qu'il a exécuté
| le 'wc -l' avant que 'grep lulu * >/dev/null' soit exécuté ! --> Comment
| peut-il savoir le résultat d'une commande qui n'est pas encore finie ?

stdout étant redirigée vers /dev/null, wc sait qu'il n'y aura rien
en entrée.


| 4) Si je fais 'grep lulu * >/dev/null | wc | wc' , j'ai toujours mes 32
| erreurs mais '1 3 24' apparait soit en première ligne, soit au milieu de
| mes erreurs et 24 est le nombre de caractères de 'grep toto * >/dev/null|wc'

Et 1 le nombre de ligne, 3 le nombre de mots.


| --> Pourquoi le résultat du dernier wc apparait il un peu au hasard ?
| Les deux programmes s'exécute en même temps ? Je pensais que le dernier
| 'wc' attendait que ce qui précède soit fini.

Du moment que le 1er wc a fini, le dernier peut calculer ce qu'il
affiche et apparaît donc dans le flux de sortie, au milieu des
messages d'erreur de grep, quand il en a la possibilité.


| Le message est un peu long, mais il m'a fallut moins de temps pour le
| rédiger que pour faire mes tests ;)
|
| Merci de m'avoir lu.

'plaisir.


Thomas
--
et quand je démarre avec STARTX ,
un gros carre blanc prend la place de mon curseur de souris !!
Le carré blanc, c'est normal c'est du X.

-+- JS in Guide du Fmblien Assassin : "Linux, c'est hard !!!" -+-

Avatar
hugolino
9 jours plus tard, je me réveille, mais c'est la réponse de SC qui
m'interpelle et me pousse à essayer de comprendre.

Le 07 Jan 2004 10:15:04 GMT, Thomas Nemeth a écrit:
Le mer 07 jan 2004 à 05:18, Hugolino a tapoté :
| Dans le script /etc/ppp/ip-up.d/fetchmail, il y a une ligne que je ne
| comprends pas:
| /etc/init.d/fetchmail awaken >/dev/null 2>&1 || /etc/init.d/fetchmail
| start


<cut>

| Si je ne veux rien voir, je fais 'toto &> /dev/null'

Connais pas, mais pourquoi pas.


T'aurais-je appris quelque chose (tu vas dire que ça n'est pas portable !)


| Mais quel peut être l'intéret de faire 'toto >/dev/null 2>&1' ?

Envoie la sortie standard stdout vers /dev/null et redirige stderr
vers stdout (donc vers /dev/null aussi).


| Mais 'toto >/dev/null 2>&1' ne donne aucune sortie,

Oui, c'est le but.


OK, mais voir plus bas...

<cut mon explication que je suis seul à comprendre ;-)>

OK, j'ai pigé, dire la commande ne donne «aucune sortie» est abusif car
elle retourne quand même un code d'erreur (0 signifiant terminaison
normale). Donc la ligne ci-dessus marche bien.


| Si je fais 'grep lulu *' j'ai 92 lignes dont 32 messages d'erreur (car
| j'ai 32 répertoires dans mon home) et ces 32 lignes d'erreur sont
| mélangées au mileu des 60 autres car grep procède dans l'ordre
| alphabetique. --> OK
|
| 1) Si je fais 'grep lulu * | wc -l' j'ai les 32 messages d'erreur *puis*
| le nombre 60. --> Bizarre pourquoi wc ne compte t-il pas les 32 lignes
| d'erreur qui doivent quand même faire partie de la sortie standard
| puisque si je ne mets pas '|wc -l' j'ai 92 lignes ??

Les 32 messages d'erreurs sont envoyés sur stderr et ton pipe ne
récupère que stdout.
grep lulu * 2>&1 | wc -l


Un pipe ne récupère que stdout, si on veut tout il faut rediriger stderr
vers stdout.


| 2) <cut Bash évalue la ligne commande avant de l'exécuter ? Oui>

| 3) Si je fais 'grep lulu * >/dev/null | wc -l', j'ai les 32 messages
| d'erreur *précédés* du chiffre '0' --> On a l'impression qu'il a exécuté
| le 'wc -l' avant que 'grep lulu * >/dev/null' soit exécuté ! --> Comment
| peut-il savoir le résultat d'une commande qui n'est pas encore finie ?

stdout étant redirigée vers /dev/null, wc sait qu'il n'y aura rien
en entrée.


De ces trois points je dois comprendre que Bash évalue la ligne de
commande avant de l'exécuter, voit que le pipe (qui ne récupère que
stdout) n'aura rien à se mettre sous la dent donc l'exécute tout de
suite puis lance ensuite le grep.
Si je fais 'grep lulu * 2>&1 | wc -l' j'obtiens bien le chiffre 32.

Mais j'ai le même résultat si je tape 'grep lulu * 2>&1 >/dev/null | wc -l'
késako ?
N'est-ce pas équivalent à 'grep lulu * >/dev/null 2>&1 | wc -l' qui
répond "0" ?

Selon moi '2>&1 >/dev/null' envoie stderr sur stdout puis stdout sur
Dave Null. Mais bien sûr c'est Bash qui commande et j'ai tort :/

HYWHM


--
Ah non ! pas exactement. Les systèmes meurent avec à leur chevet un sysadmin
désespéré. Non pas qu'il se soit pris d'affection pour ce tas de ferraille,
mais en général, l'appel pressant du youzeur devant les signes d'agonie de sa
bécane est le commencement d'un bon gros paquet d'emmerdements. -+- MA -+--