(OSX 10.7) Une application que nous utilisons nous permet d'attribuer des scripts à appeler lorsque certaines activités se déroulent dans l'application. J'ai assigné un script bash et on l'appelle, le problème est que ce que je dois faire est d'exécuter quelques commandes, d'attendre 30 secondes, puis d'exécuter d'autres commandes. Si j'ai mon script bash faire un "sommeil 30" l'application entière se fige pendant ces 30 secondes en attendant la fin de mon script.
J'ai essayé de mettre l'attente de 30 secondes (et le deuxième ensemble de commandes) dans un script séparé et d'appeler "./secondScript &", mais l'application reste là pendant 30 secondes sans rien faire. Je suppose que l'application attend le script et tous les processus enfants pour se terminer.
J'ai essayé ces variantes pour appeler le deuxième script à partir du script principal, elles ont toutes le même problème:
Je n'ai pas la possibilité de modifier l'application et de lui dire de lancer mon script sans attendre la fin.
Comment lancer un processus (je préférerais que le processus soit dans un langage de script) de sorte que le nouveau processus ne soit pas un enfant du processus actuel?
Merci, Chris
p.s. J'ai essayé la commande "désaveu" et cela n'a pas aidé non plus. Mon script principal ressemble à ceci:
[initial commands]
echo Launching second script
./secondScript &
echo Looking for jobs
jobs
echo Sleeping for 1 second
sleep 1
echo Calling disown
disown
echo Looking again for jobs
jobs
echo Main script complete
et ce que je reçois pour la sortie est la suivante:
Launching second script
Looking for jobs
[1]+ Running ./secondScript &
Sleeping for 1 second
Calling disown
Looking again for jobs
Main script complete
et à ce stade, l'application appelante reste là pendant 45 secondes, en attendant que secondScript se termine.
p.p.s
Si, en haut du script principal, j'exécute "ps", il ne renvoie que l'ID de processus de la session interactive bash que j'ai ouverte dans une fenêtre de terminal séparée.
La valeur de $ Shell est/bin/bash
Si j'exécute "ps -p $$", il me dit correctement
PID TTY TIME CMD
26884 ?? 0:00.00 mainScript
Si j'exécute "lsof -p $$", cela me donne toutes sortes de résultats (je n'ai pas collé toutes les colonnes ici en supposant qu'elles ne sont pas pertinentes):
FD TYPE NAME
cwd DIR /private/tmp/blahblahblah
txt REG /bin/bash
txt REG /usr/lib/dyld
txt REG /private/var/db/dyld/dyld_shared_cache_x86_64
0 PIPE
1 PIPE -> 0xffff8041ea2d10
2 PIPE -> 0xffff 8017d21cb
3r DIR /private/tmp/blahblah
4r REG /Volumes/DATA/blahblah
255r REG /Volumes/DATA/blahblah
La manière typique de faire cela sous Unix est de doubler une fourchette. En bash, vous pouvez le faire avec
( sleep 30 & )
(..)
crée un processus enfant et &
crée un processus de petit-enfant. Lorsque le processus enfant meurt, le processus de petit-enfant est hérité par init.
Si cela ne fonctionne pas, votre application n'attend pas de processus enfants.
Les autres éléments attendus incluent la session et les fichiers de verrouillage ouverts:
Pour créer une nouvelle session, Linux a une setsid
. Sous OS X, vous pourrez peut-être le faire via script
, ce qui crée d'ailleurs une nouvelle session:
# Linux:
setsid sleep 30
# OS X:
Nohup script -q -c 'sleep 30' /dev/null &
Pour trouver une liste de descripteurs de fichiers hérités, vous pouvez utiliser lsof -p yourpid
, qui produira quelque chose comme:
sleep 22479 user 0u CHR 136,32 0t0 35 /dev/pts/32
sleep 22479 user 1u CHR 136,32 0t0 35 /dev/pts/32
sleep 22479 user 2u CHR 136,32 0t0 35 /dev/pts/32
sleep 22479 user 5w REG 252,0 0 1048806 /tmp/lockfile
Dans ce cas, en plus des FD standard 0, 1 et 2, vous avez également un fd 5 ouvert avec un fichier de verrouillage que le parent peut attendre.
Pour fermer le fd 5, vous pouvez utiliser exec 5>&-
. Si vous pensez que le fichier de verrouillage peut être stdin/stdout/stderr eux-mêmes, vous pouvez utiliser Nohup
pour les rediriger vers autre chose.
Je pense que cela dépend de la façon dont votre processus parent essaie de détecter si votre processus enfant est terminé . Dans mon cas (mon processus parent était générique), je réussis en fermant stdout et stderr (légèrement basé sur le answer de cet autre gars ) comme ceci:
sleep 30 >&- 2>&- &
Vous pourriez aussi fermer stdin
sleep 30 <&- >&- 2>&- &
ou désavouez en outre votre processus enfant (pas pour Mac)
sleep 30 <&- >&- 2>&- & disown
Actuellement testé uniquement en bash sur kubuntu 14.04 et Mac OSX.
Une autre façon est d'abandonner l'enfant
#!/bin/bash
yourprocess &
disown
Autant que je sache, l’application remplace le shell bash normal car elle attend toujours la fin d’un processus, même si init
aurait dû s’occuper de ce processus enfant . Il se peut que le " application " intercepte la gestion des orphelins qui est normalement effectuée par init
.
Dans ce cas, seul un processus parallèle avec certains IPC peut offrir une solution (voir mon autre réponse).
Si tout échoue:
Créer un tuyau nommé
démarrez le script "lent" independent à partir de "application", assurez-vous qu'il exécute sa tâche dans une boucle infinie, en commençant par la lecture dans le tuyau. Il sera bloqué en lecture lorsqu'il essaiera de lire.
à partir de l'application, lancez votre autre script. Lorsque le script "lent" doit être appelé, il suffit d'écrire des données dans le canal. Le script lent démarrera indépendamment afin que votre script n'attende pas la fin du script "lent".
Donc, pour répondre à la question:
bash - comment puis-je lancer un nouveau processus qui n'est PAS un enfant du processus d'origine?
Simple: ne le lancez pas, mais laissez une entité indépendante le lancer pendant le démarrage ... comme init
ou à la volée avec la commande at
ou batch
Ici j'ai une coquille
└─bash(13882)
Où je commence un processus comme celui-ci:
$ (urxvt -e ssh somehost&)
Je reçois un arbre de processus (cette sortie est extraite de pstree -p
):
├─urxvt(14181)───ssh(14182)
où le processus est associé au pid 1 (systemd
dans mon cas).
Cependant, si j'avais plutôt fait ceci (notez où le &
est):
$ (urxvt -e ssh somehost)&
alors le processus serait un enfant du shell:
└─bash(13882)───urxvt(14181)───ssh(14182)
Dans les deux cas, l'invite du shell est immédiatement renvoyée et je peux exit
.__ sans mettre fin à l'arborescence des processus que j'ai démarrée ci-dessus.
Dans ce dernier cas, l’arbre de processus est reparenté sous le pid 1 lorsque Le shell se termine, de sorte qu’il se termine comme dans le premier exemple.
├─urxvt(14181)───ssh(14182)
Dans les deux cas, le résultat est un arbre de processus qui survit au shell. La seule différence Est la parenté initiale de cet arbre de processus.
Pour référence, vous pouvez également utiliser
Nohup urxvt -e ssh somehost &
urxvt -e ssh somehost & disown $!
Les deux donnent le même arbre de processus que le deuxième exemple ci-dessus.
└─bash(13882)───urxvt(14181)───ssh(14182)
Lorsque le shell est terminé, l’arbre des processus est, comme auparavant, réparéÀ pid 1.
De plus, Nohup
redirige la sortie standard du processus vers un fichier Nohup.out
. Par conséquent, s'il s'agit d'un trait utile, il peut constituer un choix plus utile.
Sinon, avec le premier formulaire ci-dessus, vous avez immédiatement un arbre de processus complètement détaché.