(bash) Script A, attendez le script B, mais pas son process fils

J'ai donc scriptA qui fait:

ssh server1 -- scriptB & ssh server2 -- scriptB & ssh server3 -- scriptB & wait otherstuffhappens 

ScriptB fait:

 rsync -av /important/stuff/. remoteserver:/remote/dir/. rsync -av /not/so/important/stuff/. remoteserver:/remote/dir/. & exit 

Mon résultat désiré est scriptA attendra que toutes les instances de ScriptB soient terminées avant de passer à autre chose, ce qui est le cas actuellement, mais il attend aussi les rsyncs d'arrière-plan des choses less importantes. Ce sont des files plus volumineux que je ne veux pas attendre.

J'ai lu la différence entre nohup, désavoué et & et essayé différentes combinaisons, mais je ne reçois pas le résultat que je cherche.

À ce stade, je suis assez perplexe. Toute aide serait appréciée!

Le problème ici est que sshd attend la fin de file sur le tuyau qu'il lit la sortie de la command (pas celle de stderr pour une raison quelconque, du less avec la version sur laquelle je teste). Et le travail d'arrière-plan hérite d'un fd à ce tuyau.

Pour contourner ce problème, redirigez la sortie de cette command rsync arrière-plan vers un file ou /dev/null si vous ne vous en souciez pas. Vous devriez également redirect stderr, car même si sshd n'attend pas le canal correspondant, après sshd , le tuyau sera brisé afin que rsync soit tué s'il tente d'écrire sur stderr.

Alors:

 rsync ... > /dev/null 2>&1 & 

Comparer:

 $ time ssh localhost 'sleep 2 &' ssh localhost 'sleep 2 &' 0.05s user 0.00s system 2% cpu 2.365 total $ time ssh localhost 'sleep 2 > /dev/null &' ssh localhost 'sleep 2 > /dev/null &' 0.04s user 0.00s system 12% cpu 0.349 total 

Et:

 $ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null &'; sleep 2; cat out 141 # ls by killed with SIGPIPE upon writing the error message $ ssh localhost '(sleep 1; ls /x; echo "$?" > out) > /dev/null 2>&1 &'; sleep 2; cat out 2 # ls exited normally after writing the error on /dev/null instead # of a broken pipe 

Écrire un script qui est le parent des deux, alors vous pouvez facilement contrôler les deux . Alternativement, établir un canal de communication entre les deux canaux .

Pour ignorer spécifiquement certains travaux en arrière-plan, vous pouvez capturer le PID ( $! Est le dernier PID du travail en arrière-plan) et wait $pid pour attendre que ce travail soit terminé.

L' -f de ssh corrige le problème. Testé le:

 #!/bin/sh -e echo $$_script__begin ( echo sleeping; sleep 2; echo slept )& echo $$_script__end 

Quand je l'exécute avec ssh localhost ./script , il attend jusqu'à ce que ssh localhost ./script apparaisse. Avec le drapeau -f , il sort à echo $$_script__end et slept plus tard apparaît en arrière-plan après le return de la command ssh .

C'est un problème connu du server OpenSSH, qui est décrit et discuté dans bugzilla # 2071 en amont. Dans le bogue, plusieurs solutions de contournement sont proposées, soit du côté OpenSSH, mais aussi pour le script.

Si vous voulez attendre la sortie des scripts, vous devez également append une wait avant de exit le scriptB également.

Si vous ne vous souciez pas de la sortie, utilisez une variante de nohup et IO redirection vers /dev/null , ce qui résoudra le problème de la même façon.

Vous pouvez essayer ceci. $! est une variable shell par défaut qui contient l'ID de process du pipeline / process en arrière-plan le plus récemment exécuté.

 command1 & lpid1=$! command2 & lpid2=$! command3 & lpid=$! wait $lpid1 # waits for only the process with PID lpid1 to complete. 

Vous devez utiliser cela selon votre script en utilisant export variable d' export etc

B doit juste attendre ses propres process d'arrière-plan:

 rsync -av /important/stuff/. remoteserver:/remote/dir/. rsync -av /not/so/important/stuff/. remoteserver:/remote/dir/. & wait exit