web-dev-qa-db-fra.com

Comment puis-je lancer un nouveau processus qui n'est PAS un enfant du processus d'origine?

(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:

  • Nohup ./secondScript &
  • ((./secondScript &) &)
  • (./secondScript &)
  • Nohup script -q/dev/null secondScript &

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
17
Betty Crokker

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.

23
that other guy

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.

11
Joe

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).

11
thom

Si tout échoue:

  1. Créer un tuyau nommé

  2. 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.

  3. à 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

1
thom

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é.

0
starfry