OVH Cloud OVH Cloud

script shell pere et fils

13 réponses
Avatar
octane
Bonjour,
[Systeme linux]

j'ai un script bash pere qui lance des scripts bash fils

Ces fils doivent afficher des retours a l'ecran.
Ils n'affichent pas ce que je veux lorsque je leur envoie un signal.

Premier cas, qui fonctionne:
aaa@darkstar:~$ cat fils
#! /bin/bash
PID=3D$$
mort()
{
echo "je suis tue par un INT"
exit 0
}
trap mort INT
echo je suis le fils et mon PID est $PID
while [ true ]
do
true
done
aaa@darkstar:~$ ./fils
je suis le fils et mon PID est 16036

(depuis une deuxieme console, je lance un kill -INT 16036)

je suis tue par un INT
aaa@darkstar:~$

Maintenant avec un pere:
aaa@darkstar:~$ cat pere
#! /bin/bash
echo "je suis le pere"
./fils &
sleep 30
aaa@darkstar:~$./pere
je suis le pere
je suis le fils et mon PID est 16039

(envoi d'un kill -INT 16039 --> rien!)
(envoi d'un kill -9 16039 -> le fils meurt)
(30 secondes plus tard)
./pere: line 4: 16039 Processus arr=EAt=E9 ./fils
aaa@darkstar:~$

1=2E pourquoi le fils ne meurt pas lors du INT?
2=2E comment faire pour que le fils affiche sur la console sa
mort?

Merci

10 réponses

1 2
Avatar
Pascal Bourguignon
writes:

Bonjour,
[Systeme linux]

j'ai un script bash pere qui lance des scripts bash fils

Ces fils doivent afficher des retours a l'ecran.
Ils n'affichent pas ce que je veux lorsque je leur envoie un signal.
[...]
1. pourquoi le fils ne meurt pas lors du INT?


Le fils meurt (ps axf), mais il ne semble pas exécuter sa trap.
Même si on le lance avec ./fils & disown dans le pere....


2. comment faire pour que le fils affiche sur la console sa
mort?


Je ne sais pas comment faire. Ça ressemble à une belle bogue dans bash...


Je conseillerais d'utiliser un vrai langage de programmation:

[ tmp]$ ./pere.lisp
Le père: Je suis le père
Le fils: Je suis le fils, PID = 5661
Exiting on signal 15

Le fils: On m'a tué!
Le père: j'ai fini.
[ tmp]$ cat pere.lisp
#!/usr/local/bin/clisp -q -ansi -norc -Kfull
(format t "~&Le père: Je suis le père~%")
(finish-output)
(ext:run-program "./fils.lisp" :wait nil)
(sleep 30)
(format t "~&Le père: j'ai fini.~%")
(finish-output)
[ tmp]$ cat fils.lisp
#!/usr/local/bin/clisp -q -ansi -norc -Kfull
(format t "~&Le fils: Je suis le fils, PID = ~D~%" (linux:getpid))
(finish-output)
(unwind-protect
(loop (sleep 10))
(format t "~%Le fils: On m'a tué!~%")
(finish-output))
[ tmp]$


--
__Pascal Bourguignon__ http://www.informatimago.com/

"Do not adjust your mind, there is a fault in reality"
-- on a wall many years ago in Oxford.

Avatar
Xavier Gachon
Le 03-01-2006, Pascal Bourguignon a écrit :
writes:
1. pourquoi le fils ne meurt pas lors du INT?



peut etre par ce que les process asynchrone qui n'ont pas le job control
(et/ou ne sont pas/plus en foreground) ne traitent pas SIGINT, un trap -p
INT derriere le trap mort INT devrait te confirmer que rien n'est
positionné dans le fils.

mais il est vrai que ce n'est pas evident de s'y retrouver dans la doc
un mix du man bash et de la doc texinfo de la libc (glibc j'imagine) aux
sections "Job Control" me semble une bonne piste ;)

Le fils meurt (ps axf),


via un sigintr sur un sous shell... voila un comportement bien plus
etrange que je n'ais pu reproduire que ce soit sous bash, zsh ou
un quelconque bourne like.

2. comment faire pour que le fils affiche sur la console sa
mort?



utiliser un autre signal (au hasard ton exemple devrait fonctionner avec
USR1), faire en sorte que ce soit le pere qui annonce la mort du fils
a la suite d'un wait, autres...

Je conseillerais d'utiliser un vrai langage de programmation:

[ tmp]$ ./pere.lisp
Le père: Je suis le père
Le fils: Je suis le fils, PID = 5661
Exiting on signal 15
aheummm...


sans doute n'as tu jamais envisagé qu'un proselitisme idiot
pour un langage quel qu'il soit pouvait s'averer contre productif
ou pire pour le langage en question...

xavier.


Avatar
Vincent Lefevre
Dans l'article ,
Xavier Gachon écrit:

Le 03-01-2006, Pascal Bourguignon a écrit :
writes:
1. pourquoi le fils ne meurt pas lors du INT?



peut etre par ce que les process asynchrone qui n'ont pas le job control
(et/ou ne sont pas/plus en foreground) ne traitent pas SIGINT, un trap -p
INT derriere le trap mort INT devrait te confirmer que rien n'est
positionné dans le fils.


Le trap n'est-il justement par là pour redéfinir le traitement du
signal INT?

Sinon j'avais déjà eu des problèmes, par exemple lorsqu'il y a un trap
et que le processus bash fait un sleep, le signal n'est pris en compte
qu'à la fin du sleep (quelque chose de ce genre). Mais là, ça semble
encore plus bizarre.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA



Avatar
Vincent Lefevre
Dans l'article ,
Xavier Gachon écrit:

Le 03-01-2006, Pascal Bourguignon a écrit :
writes:
1. pourquoi le fils ne meurt pas lors du INT?



peut etre par ce que les process asynchrone qui n'ont pas le job control
(et/ou ne sont pas/plus en foreground) ne traitent pas SIGINT, un trap -p
INT derriere le trap mort INT devrait te confirmer que rien n'est
positionné dans le fils.


Effectivement, une commande "trap" toute seule ne liste pas le trap
en cas de lancement par "pere".

prunille:~> ./fils &
[1] 13107
trap -- 'mort' SIGINT
je suis le fils et mon PID est 13107

Mais:

prunille:~> ./pere
je suis le pere
je suis le fils et mon PID est 13116

mais il est vrai que ce n'est pas evident de s'y retrouver dans la doc
un mix du man bash et de la doc texinfo de la libc (glibc j'imagine) aux
sections "Job Control" me semble une bonne piste ;)


La page man de bash dit:

SIGNALS
When bash is interactive, in the absence of any traps, it ignores
SIGTERM (so that kill 0 does not kill an interactive shell), and SIGINT
is caught and handled (so that the wait builtin is interruptible). In
all cases, bash ignores SIGQUIT. If job control is in effect, bash
ignores SIGTTIN, SIGTTOU, and SIGTSTP.

Non-builtin commands run by bash have signal handlers set to the values
inherited by the shell from its parent. When job control is not in
effect, asynchronous commands ignore SIGINT and SIGQUIT in addition to
these inherited handlers. Commands run as a result of command substi-
tution ignore the keyboard-generated job control signals SIGTTIN, SIGT-
TOU, and SIGTSTP.

Apparemment dans ce cas, SIGINT et SIGQUIT sont toujours ignorés, même
quand on essaie de les positionner par un trap. POSIX dit (mais ça ne
me semble pas clair):

http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_11

2.11 Signals and Error Handling

When a command is in an asynchronous list, the shell shall prevent
SIGQUIT and SIGINT signals from the keyboard from interrupting the
command. Otherwise, signals shall have the values inherited by the
shell from its parent (see also the trap special built-in).

Noter le "from the keyboard". Est-ce que cela signifie que quand on
fait un Ctrl- ou un Ctrl-C, le signal correspondant ne doit pas être
envoyé au processus, ou est-ce que cela veut dire que les SIGQUIT et
SIGINT doivent toujours (même en cas de trap) être ignorés (mais alors
le clavier n'a rien à voir là-dedans)?

En tout cas, zsh n'a pas le même comportement que bash: la commande
trap est toujours prise en compte.

2. comment faire pour que le fils affiche sur la console sa
mort?



utiliser un autre signal (au hasard ton exemple devrait fonctionner
avec USR1), [...]


ou TERM, qui est plutôt fait pour cela.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA



Avatar
Xavier Gachon
Le 04-01-2006, Vincent Lefevre <vincent+ a écrit :
Dans l'article ,
Xavier Gachon écrit:

Le 03-01-2006, Pascal Bourguignon a écrit :
writes:
1. pourquoi le fils ne meurt pas lors du INT?



peut etre par ce que les process asynchrone qui n'ont pas le job control
(et/ou ne sont pas/plus en foreground) ne traitent pas SIGINT, un trap -p
INT derriere le trap mort INT devrait te confirmer que rien n'est
positionné dans le fils.


Le trap n'est-il justement par là pour redéfinir le traitement du
signal INT?


entre autres oui, mais manisfestement pas dans tout les contextes,
extraits du man bash:

When bash is interactive, in the absence of any traps, it ignores
SIGTERM (so that kill 0 does not kill an interactive shell), and SIGINT
is caught and handled (so that the wait builtin is interruptible)
...
When job control is not in effect, asynchronous commands ignore SIGINT
and SIGQUIT in addition to these inherited handlers.

le signal n'est pris en compte qu'à la fin du sleep (quelque chose de ce
genre).


ca c'est un cas d'ecole dont on trouve facilement des exemples sur google,
contrairement aux divers comportements et influences du job control sur
le traitement des signaux ;)

xavier.




Avatar
Vincent Lefevre
Dans l'article ,
Xavier Gachon écrit:

When bash is interactive, in the absence of any traps, it ignores
SIGTERM (so that kill 0 does not kill an interactive shell), and SIGINT
is caught and handled (so that the wait builtin is interruptible)
...
When job control is not in effect, asynchronous commands ignore SIGINT
and SIGQUIT in addition to these inherited handlers.


Et que penses-tu de ce que j'ai dit dans mon autre réponse concernant
ce point-là?

le signal n'est pris en compte qu'à la fin du sleep (quelque chose
de ce genre).


ca c'est un cas d'ecole dont on trouve facilement des exemples sur
google,


Oui, enfin le sh de Solaris ne se comporte pas comme cela (mais il
n'est pas POSIX), alors quand j'ai migré, c'était plutôt surprenant.
En tout cas, le fait qu'un signal handler ne puisse pas être exécuté
immédiatement quand le signal est reçu et doive attendre la fin de
la commande élimine les shells comme langages de programmation quand
on veut une gestion avancée avec les signaux.

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
Xavier Gachon
Le 04-01-2006, Vincent Lefevre <vincent+ a écrit :
Dans l'article ,
Xavier Gachon écrit:
[snip]

When job control is not in effect, asynchronous commands ignore SIGINT
and SIGQUIT in addition to these inherited handlers.


Et que penses-tu de ce que j'ai dit dans mon autre réponse concernant
ce point-là ?


Je n'ai reçu l'autre qu'apres ma réponse a la premiere, feed uucp
pas synchrone du tout oblige, désolé ;)

comme j'y faisais reference dans mon premier post, le job control et plus
particulierement le rapport entre les jobs/pilelines/process asynchrone et
le terminal (physique ou virtuel, donc pas necessairement lié au clavier)
n'est pas etrangé a ce comportement.

je reprend donc ton second message ici:
Noter le "from the keyboard". Est-ce que cela signifie que quand on
fait un Ctrl- ou un Ctrl-C, le signal correspondant ne doit pas être
envoyé au processus, ou est-ce que cela veut dire que les SIGQUIT et
SIGINT doivent toujours (même en cas de trap) être ignorés (mais alors
le clavier n'a rien à voir là-dedans) ?


Cela veut dire que le signal correspondant ne doit etre envoyé qu'aux
processus dont le "process group ID" est egal au "current terminal
process group ID", ou tout au moins que seuls ceux-ci ne doivent pas
l'ignorer. C'est ce qui differencie les job de foreground de ceux
de background, et la raison pour laquelle j'avais orienté sur ces
sections de la documentation bash/libc.

Si l'on reprend l'exemple d'origine avec 2 scripts pere et fils en bash
et lancés sous bash. Le bash a partir duquel on lance le pere a generalement
le job control (sous Linux au moins). Selon l'extrait de doc ci-dessus le
job pere ne doit donc pas ignorer le SIGINT, mais il n'a plus le job control
par defaut (un echo $- devrait confirmer), il lancera donc le process fils
sans job control et en asynchrone raison pour laquelle ce dernier ne traite
plus le SIGINT (doc). On peut modifier ce comportement en rajoutant un
"set -m" dans le pere mais dans ce cas le fils n'aurat plus le meme PGID
que le pere et s'il traitera un SIGINT "quelconque", il ignorera le SIGINT
clavier qui flinguera donc le pere mais pas lui.

Si par contre au lieu de lancer 2 scripts, le fils n'est qu'un pipeline
du pere sans les phases d'initialisations du shell pour le script, genre:

echo pere
{ echo fils; while :; do :; done ; } &
while :; do :; done ;

alors le pere et le fils conservent le meme PGID et seront tout deux
fligués par un SIGINT clavier.

enfin qqchose comme ca... j'ai deja mal a la tete, le mieux serait
sans doute de ne pas bosser aujourd'hui %)

En tout cas, zsh n'a pas le même comportement que bash: la commande
trap est toujours prise en compte.


effectivement j'ai du merder en testant, ptet oublié de remplacer
les #!/bin/bash des scripts par des #!/bin/zsh :)

élimine les shells comme langages de programmation quand
on veut une gestion avancée avec les signaux.


Ce n'est sans doute pas l'unique comportement les disqualifiant
pour nombre de choses; En meme temps si ces autres langages de
programmation etaient conçus pour etre utilisé _entre_autres_
de façon interactive pour faire tourner des unix, ils seraient
egalement consideré comme des shells, au meme titre que scsh,
csh, et d'autres ;)

bonne journée, xavier.

ps (private joke): s'qu'y'a de bien sur Usenet c'est de ne
plus avoir besoin d'une signature a la con pour que le message
arrive a destination ;)


Avatar
Vincent Lefevre
Dans l'article ,
Xavier Gachon écrit:

je reprend donc ton second message ici:
Noter le "from the keyboard". Est-ce que cela signifie que quand on
fait un Ctrl- ou un Ctrl-C, le signal correspondant ne doit pas être
envoyé au processus, ou est-ce que cela veut dire que les SIGQUIT et
SIGINT doivent toujours (même en cas de trap) être ignorés (mais alors
le clavier n'a rien à voir là-dedans) ?


Cela veut dire que le signal correspondant ne doit etre envoyé qu'aux
processus dont le "process group ID" est egal au "current terminal
process group ID", ou tout au moins que seuls ceux-ci ne doivent pas
l'ignorer. C'est ce qui differencie les job de foreground de ceux
de background, et la raison pour laquelle j'avais orienté sur ces
sections de la documentation bash/libc.


Oui, c'est documenté dans le man de bash (la libc n'a rien à faire
ici, d'ailleurs zsh avec la même libc se comporte différemment).
Mais d'après ce que tu dis (et c'était aussi mon interprétation),
bash n'est pas conforme à POSIX (et zsh l'est).

Si l'on reprend l'exemple d'origine avec 2 scripts pere et fils en
bash et lancés sous bash. Le bash a partir duquel on lance le pere a
generalement le job control (sous Linux au moins). Selon l'extrait
de doc ci-dessus le job pere ne doit donc pas ignorer le SIGINT,
mais il n'a plus le job control par defaut (un echo $- devrait
confirmer), il lancera donc le process fils sans job control et en
asynchrone raison pour laquelle ce dernier ne traite plus le SIGINT
(doc). On peut modifier ce comportement en rajoutant un "set -m"
dans le pere mais dans ce cas le fils n'aurat plus le meme PGID que
le pere et s'il traitera un SIGINT "quelconque", il ignorera le
SIGINT clavier qui flinguera donc le pere mais pas lui.


Ce n'est pas qu'il l'ignorera, c'est qu'il ne le recevra même pas.
La différence est importante, car la spécification de trap de POSIX
http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html
dit:

"Signals that were ignored on entry to a non-interactive shell
cannot be trapped or reset, although no error need be reported
when attempting to do so."

Il se trouve que d'après la doc de bash, si l'utilisateur envoie
un SIGINT (e.g. par la commande kill), alors il sera effectivement
ignoré, bien que POSIX ne dise nulle part qu'il doit être ignoré
(il n'y a donc aucune raison de faire une exception).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / SPACES project at LORIA


Avatar
octane
Merci a tous ceux qui m'ont repondu.

J'ai resolu le probleme, mais sans vraiment comprendre.
Le script fils, en gros, correspond a
:~$ cat fils
#! /bin/bash
PID=$$
mort()
{
echo "je suis tue par un SIGQUIT"
exit 0
}
trap mort SIGQUIT
echo je suis le fils et mon PID est $PID
while [ true ]
do
true
done

Sauf que dans mon cas réel, la boucle while comporte
beaucoup plus d'actions.

Avec ce script fils simpliste, ca ne fonctionne pas

Avec le vrai programme shell, ca fonctionne.

Curieux.
Avatar
Xavier Gachon
Le 05-01-2006, Vincent Lefevre <vincent+ a écrit :
raison pour laquelle j'avais orienté sur ces sections de la
documentation bash/libc.
Oui, c'est documenté dans le man de bash (la libc n'a rien à faire

ici, d'ailleurs zsh avec la même libc se comporte différemment).


La _doc_ de la libc qui se veut +-POSIX se repand en long en
large et en traver sur les details du job control, contrairement
a POSIX lorsqu'on se limite aux sections shell. Parler de conformité
POSIX hors libc est un tantinet osé!

Mais d'après ce que tu dis (et c'était aussi mon interprétation),


Tu aurais du l'explicité; nous aurions gagné du temps.

bash n'est pas conforme à POSIX (et zsh l'est).


C'est un peu court, allez hop, le reste de ton message n'explique pas
pourquoi zsh lorsque le fils est asynchrone laisse celui-ci recevoir
et/ou traiter le INT clavier contrairement au premier paragraphe du
"2.11 Signal and Error Handling" de POSIX (vu precedemment) et a bash.
Donc, d'apres notre interpretation, aucun des deux n'est POSIX, dur!
pi la sortie (au moins par defaut) de jobs -p sous zsh n'est pas conforme
et ca c'est grave!!! %)</grin>

Mais je ne me jetterais pas dans une discussion sur la conformité
POSIX (sans meme parler des versions/evolutions de celle-ci) d'un
shell quelconque ici. C'est le genre de sujet a peter les plombs
a court terme vu la gueule de POSIX; Meme les discussions sans fin
concernant la conformités de compilateurs de langages divers et variés
a des normes ISO (ou pas :) sont moins casse gueule... lorsqu'en plus il
semble y avoir un parti pris, bonjour l'horreur, et je ne parle meme
pas de la validité/coherence du contenu des normes/specs/std en
question :-)

xavier.


1 2