Bash : rend la main... ou pas

Hello,

Petite question vite fait.

Je suis en de travailler le bash. Je me suis donc écrit un petit script (juste une exemple, en fait :

nl toto2

 1  #!/bin/bash
 2  { cd /home ; ls ; cd  /home/bash* ;ps;}&

si je le lance, j’obtiens ceci :
sh-3.2# toto2
sh-3.2# bash_scripts image lib64 lost+found opt scripts test.txt
christian lib logs.tar.gz Masteradm01 samba sysvarfx vsftpd
PID TTY TIME CMD
27576 pts/1 00:00:00 sh
32477 pts/1 00:00:00 toto2
32479 pts/1 00:00:00 ps

On a donc un shell enfant qui est créé (ayant placé mon exécution en tâche de fond). Bien, mais, il semble que je devrais retrouver la main et obtenir un truc du style : “[1] + Done” à la fin. Ce qui n’est pas le cas.

Lorsque vous lancez un script en tâche de fond, vous Shell vous rends la main, à vous? Ou il y a une configuration spécifique, pour le récupérer?

Il suffit de rajouter « & » à la fin de la commande pour que le shell rende la main :

Tu peux même utiliser nohup, si tu veux pouvoir fermer ton terminal, et laisser ta commande s’exécuter en tache de fond :

J’ai mis le prompt root (#) car c’est ce que tu as mis dans ton exemple. Mais ça fonctionne aussi en user.
D’ailleurs, si tu fais des scripts pour faire des tests ou t’amuser, lances les en user (si le script ne fait pas ce à quoi tu t’attends, ça peut te sauver).

mmmmm nan, je ne crois pas : le “&” est déjà dans le script :slightly_smiling:. C’est même justement pour ça que je me pose la question. :s

Non, le script se termine normalement et le shell ne remarque rien (pour lui, il n’y a pas eu de tache mise en arrière fond), par contre après le script ait fini et que le shell te rende la main, la tache se continue et produit les sorties:

#!/bin/sh { cd /home ; ls ; cd /home/bash* ;ps;}& echo gabeuzou

puis

[code]francois@bling:~$ sh /tmp/grp # le script se lance
gabeuzou # le script est terminé voir le prompt jute après
francois@bling:~$ francois furst lenny lost+found racine
/tmp/grp: line 2: cd: /home/bash*: Aucun fichier ou répertoire de ce type
PID TTY TIME CMD
16839 pts/2 00:00:00 bash
17557 pts/2 00:00:00 sh
17559 pts/2 00:00:00 ps

ici je suis au prompt normal, si je tapes entrée

francois@bling:~$ # j’onbtiens le prompt
[/code]

Salut Fran!

J’ai ajouté une ligne :
1#!/bin/bash
2
3 { cd /home ; ls ; cd /home/bash* ;ps;}&
4
5 echo “toto tombe a l’eau - EOF”

Par contre, si je lance le script :
toto tombe a l’eau - EOF
sh-3.2# bash_scripts image lib64 lost+found opt scripts test.txt
christian lib logs.tar.gz Masteradm01 samba sysvarfx vsftpd
PID TTY TIME CMD
3445 pts/0 00:00:00 sh
3485 pts/0 00:00:00 bash
3487 pts/0 00:00:00 ps

sh-3.2#

Je retrouve donc le prompt en tapant sur la touche entrée. Bizarrement, je n’ai pas “toto tombe à l’eau - EOF”. Cela s’arrête à l’exécution de la commande ps" (je devrais peut-être essayer avec la commande UMP… humpf!).

je n’ai peut-être pas bien compris ton retour, à propos de “gabeuzou”. Tu obtiens ce résultat avant l’exécution de la commande ps? après? pas du tout? Selon toi, il est normal que je n’obtienne pas de “[1] + Done” (ou équivalent) et qu’il me faille taper sur entrée?

Salut,

C’est normal que tu n’obtienne pas le [1] Done…
Comme tu le dis, la partie {cd /home… } & se fait en background d’un nouveau environnement bash.

Tu peux modifier ton script pour envoyer le résultat d’echo dans un fichier ainsi :
echo “Ton texte” > /tmp/log

Tu aura alors un fichier /tmp/log avec “Ton test”

[quote]Par contre, si je lance le script :
toto tombe a l’eau - EOF
sh-3.2# bash_scripts image lib64 lost+found opt scripts test.txt
christian lib logs.tar.gz Masteradm01 samba sysvarfx vsftpd
PID TTY TIME CMD
3445 pts/0 00:00:00 sh
3485 pts/0 00:00:00 bash
3487 pts/0 00:00:00 ps
[/quote]Si tu l’as mais avant… C’est normal, le bash continue sur sa lancée et prend de l’avance par rapport à son fils, le temps que le noyau le crée…

Mmm étant donné que l’histoire des shells enfants est fondamental, j’insiste un peu.
Quand on lance un processus en fond de tâche, comme ceci, un shell enfant est crée. Le processus qui est lancé est donc exécuté dans ce sous-shell. Ok.

Techniquement, si j’intègre mon “echo toto” entre les accolades, je vois apparaitre la phrase. Ca je comprends, car l’exécution de l’instruction se fait dans le même shell enfant que les autres opérations.

Si je ne le fais pas, autrement dit, si je demande l’exécution de cet “echo toto” comme une instruction séparée, cela voudrait dire que j’en demande l’exécution dans le shell père (vous me dites si je me trompes). Ce qui ne se produit pas car pour que ce soit le cas, il faudrait que le shell enfant “meure” après avoir terminé l’exécution des instructions demandées en fonds de tâche.

Or, précisément, ce n’est pas le cas. Le shell enfant ne meure pas. Il garde la main, empêchant l’exécution de la suite des instructions.

C’est donc là où je ne comprends pas : que faudrait-il ajouter pour que le shell enfant rende la main?
Naturellement, la réponse est peut-être dans vos retours… et je ne l’ai peut-être pas compris?
Ou bien, je dois absolument passer par une redirection de la sortie standard dans un fichier /tmp pour finir le processus enfant, comme le suggère Capcorn?

Dsl si j’ai l’air d’un gros lourd… mais avant de passer à la suite, je dois bien maitriser cet aspect là du bash (le problème, ici, n’est pas la compréhension du code en soi - j’ai fait du perl et je n’ai pas le souvenir d’avoir connu cette problématique - mais la façon dont le shell gère les processus). :slightly_smiling: :confused:
Mais bien sûr je suis peut-être à côté de la plaque dans mon raisonnement…

Merci d’avance :slightly_smiling:

Re,

Si le processus fils se termine mais on ne le vois pas.

La preuve, avec ce code :

#!/bin/bash

{ cd /home ; ls ;ps; } &

echo "coucou" > /tmp/log

Le fichier /tmp/log se crée bien et il contient bien le “coucou”, donc le processus père reprend bien la main et exécute le echo

J’ai l’impression en effet :

[quote=“fran.b”][quote]Par contre, si je lance le script :
toto tombe a l’eau - EOF
sh-3.2# bash_scripts image lib64 lost+found opt scripts test.txt
christian lib logs.tar.gz Masteradm01 samba sysvarfx vsftpd
PID TTY TIME CMD
3445 pts/0 00:00:00 sh
3485 pts/0 00:00:00 bash
3487 pts/0 00:00:00 ps
[/quote]Si tu l’as mais avant… C’est normal, le bash continue sur sa lancée et prend de l’avance par rapport à son fils, le temps que le noyau le crée…[/quote]
Autrement dit : Vu que tu termines la première ligne par un « & », la deuxième est lancée en même temps. Etant donnée qu’elle va être éxécutée plus rapidement (pas de shell enfant à créer, pas de cd /home à faire avant), tu verras le résultat de la deuxième commande avant la première.

Ah d’ac. Effectivement, je confirme :

sh-3.2# bash toto2
toto tombe a l’eau - EOF
sh-3.2# cat /tmp/toto
(…)
vsftpd
PID TTY TIME CMD
3445 pts/0 00:00:00 sh
10096 pts/0 00:00:00 bash
10099 pts/0 00:00:00 ps
sh-3.2#

Bon, ok : la création d’un sous-shell prends plus de temps (logique, en effet). Résultat : “toto tombe a l’eau” apparait avant. Ok.
Pigé.
Effectivement, une redirection me renvoie le résultat dans /tmp/toto. Ok. Ce qui montre que le processus fait bien son travail. Nickel.

Je comprends toute cette partie là.
Impeccable bien. Merci pour les explications (vraiment :slightly_smiling: Tout ceci est très intéressant).

Maintenant, ce que je ne pige tjs pas, c’est : dès lors les processus père et enfants sont exécutés, dès lors que le processus enfant rends la main, pourquoi est-ce que je dois taper “entrée” pour récupérer le prompt? je ne devrais pas pouvoir le récupérer directement ?

L’exécution d’un processus en fond de tâche - peu importe lequel - dans la machine, en shell, ne nous empêche pas de basher par ailleurs, non? (l’OS serait impraticable, autrement).

En fait c’était la même chose lorsque je lançais un startx sur mon serveur. Il me fallait taper sur entrée pour reprendre la main, sauf que là… (de mémoire) ça interrompait du même coup le fonctionnement (qui ne fonctionne toujours pas, soit dit en passant) de mon serveur X (en gros, ça tuait le processus “X”.).

D’ailleurs, cette vieille histoire est l’une des raisons - et un bon exemple - qui me pousse à poser ces questions : un jour ou l’autre je reviendrai sur ce problème, et j’ai besoin de comprendre ce qui se passe (au pire, je réinstalle tout… ouch! Je sais, François : c’est mal. LOL :slightly_smiling: je plaisante : je sais très bien pourquoi tu ne le préconise pas. Ce n’est pas ainsi que je comprendrai ce qui s’est passé, et ce n’est pas non plus ainsi que je pourrai résoudre le problème s’il se représente).

Je ne suis pas sur qu’il ne te rend pas la main…
Est-ce que tu peux essayer de faire ceci :
[ul]
[li]executer ton script sans faire entrer à la fin;[/li]
[li]puis faire ls puis entrer[/li][/ul]

Le résultat te permettra de mieux comprendre…

Tu as déjà récupéré le prompt, il est là en rouge. Simplement, il y a eu des sorties à coté. Tu n’as qu’à lancer le script en redirigeant la sorte dans /tmp/gre, tu verras mieux…

[quote]toto tombe a l’eau - EOF
sh-3.2# bash_scripts image lib64 lost+found opt scripts test.txt
christian lib logs.tar.gz Masteradm01 samba sysvarfx vsftpd
PID TTY TIME CMD
3445 pts/0 00:00:00 sh
3485 pts/0 00:00:00 bash
3487 pts/0 00:00:00 ps[/quote]

Oui, lol.

Je l’ai récupéré parce que, précisémment, j’ai tapé entrée. Et si je le redirige dans un /temp/fic, effectivement, je le récupère vraiment. Dans le cas d’une redirection vers un fichier, je récupère le prompt aussi sec.

Si je dirige le résultat - on va dire “par défaut”, sur la sortie standard, le processus est exécuté, mais je ne récupère pas le prompt tant que je n’ai pas tapé “entrée”.

A noter que vos explications m’ont donné la bonne idée d’utiliser “sleep” :

sh-3.2# nl toto2
1 #!/bin/bash

 2  { cd /home ; ls ; cd  /home/bash* ;ps ; } >/tmp/toto &
 3  echo "toto tombe a l'eau - EOF"
 4  sleep 1
 5  cat /tmp/toto

sh-3.2#

Ainsi, de cette façon, je peux voir le résultat dans /tmp/toto. Sans le sleep, le shell père est trop rapide pour le shell enfant, et le cat est exécuté avant que la redirection soit effectuée :slightly_smiling:. Bon, c’est bateau comme pas possible, mais ça illustre très bien votre explication.

Et… ah!
J’ai ensuite modifié mon script comme suit :
sh-3.2# nl toto2
1 #!/bin/bash

 2  { cd /home ; ls ; cd  /home/bash* ;ps ; }&
 3  echo "toto tombe a l'eau - EOF"
 4  sleep 1

sh-3.2#

Et là, Ô suprise :

bash_scripts image lib64 lost+found opt scripts test.txt
christian lib logs.tar.gz Masteradm01 samba sysvarfx vsftpd
PID TTY TIME CMD
30779 pts/1 00:00:00 sh
30848 pts/1 00:00:00 bash
30849 pts/1 00:00:00 bash
30851 pts/1 00:00:00 sleep
30852 pts/1 00:00:00 ps
sh-3.2#

Cette fois je récupère directement le prompt. Ce n’est plus le cas si je commente le “sleep”.
Et notez au passage que si je fais un ls, dans ce cas précis, j’obtiens :

christian lib logs.tar.gz Masteradm01 samba sysvarfx vsftpd
PID TTY TIME CMD
30779 pts/1 00:00:00 sh
30865 pts/1 00:00:00 bash
30867 pts/1 00:00:00 ps
ls
char-gen ex2-1 ex5 ex7 maj_paquets sysvar toto2 webmitm.crt
echo ex3 ex6 ex7-1 nohup.out tes2 toto3
ex1 ex3-1 ex6-1 ex8 ntest test trace1
ex2 ex4 ex6-2 fic nvtest toto trace2
sh-3.2#

J’ai donc le prompt, dans ce cas, après avoir lancé le ls. So what? L’exécution de la commande ls se fait dans le sous-shell? Ou bien, au contraire, elle s’effectue dans le shell père et dans ce cas, il ne s’agit que d’une histoire de prompt non-apparent?
:s

[quote=“sonador”]Oui, lol.

Je l’ai récupéré parce que, précisémment, j’ai tapé entrée. Et si je le redirige dans un /temp/fic, effectivement, je le récupère vraiment. Dans le cas d’une redirection vers un fichier, je récupère le prompt aussi sec.

Si je dirige le résultat - on va dire “par défaut”, sur la sortie standard, le processus est exécuté, mais je ne récupère pas le prompt tant que je n’ai pas tapé “entrée”.[/quote]
Mais si tu le récupères, mais après le prompt (que j’ai mis en rouge) s’affiche enfin les sorties de ta tache de fond, le bash n’est pas au courant et ne te remet pas un deuxième prompt sauf si tu tapes entrée…

Je te fais le script:

[quote]francois@bling:~$ cat /tmp/g
#!/bin/bash

{ cd /home ; ls ; cd /home/bash* ;ps ; }&
echo “toto tombe a l’eau - EOF”
(* C’est donc ton script *)
francois@bling:~$ sh /tmp/g (* éxecution du script *)
toto tombe a l’eau - EOF (* la le texte est affiché *)
francois@bling:~$(* et là le prompt *) francois francois.ubuntu furst lenny lost+found racine
/tmp/g: line 3: cd: /home/bash*: Aucun fichier ou répertoire de ce type
PID TTY TIME CMD
14755 pts/6 00:00:00 bash
14786 pts/6 00:00:00 sh
14788 pts/6 00:00:00 ps
(* puis tes différentes sorties *)
[/quote]

Ok, si je comprends bien : c’est plus une question de séquençage dans l’exécution. Parce que le résultat de ps apparait après le retour du prompt, nous avons ce phénomère.

-Après soit avec le sleep, le père rend le prompt après l’exeuction complète du fils (je suis tom père!.. Nooooon!).

-soit y a pas de sleep (et faut pas sortir dehors, dans ce cas), le père est exécuté logiquement plus rapidement que le fils et affiche le prompt. Le fils affiche alors son résultat mais n’est pas sensé refiler un prompt, étant le rôle du père. Son rôle se limitant à exécuter ce qu’on lui demande en sortie standard (ou dans un fichier, dans le cas d’une redirection dans /temps/qqchose).

Pour résumer, ce serait le principe.