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