(bash) Script A, attendi lo script B, ma non il suo processo figlio


9

Quindi ho scriptA che fa:

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

ScriptB fa:

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

Il mio risultato desiderato è scriptA attenderà il completamento di tutte le istanze di script B prima di procedere, cosa che attualmente fa, tuttavia sta anche aspettando i rsync in background delle cose non così importanti. Questi sono file più grandi che non voglio aspettare.

Ho letto la differenza tra nohup, disown e & e ho provato diverse combinazioni, ma non sto ottenendo il risultato che sto cercando.

A questo punto sono piuttosto perplesso. Qualsiasi aiuto sarebbe apprezzato!

Risposte:


15

Il problema qui è che sshdattende la fine del file sulla pipe da cui sta leggendo lo stdout del comando (non quello stderr per qualche motivo, almeno con la versione su cui sto testando) da. E il lavoro in background eredita un fd in quella pipe.

Quindi, per ovviare a questo, reindirizza l'output di quel rsynccomando in background su un file o /dev/nullse non ti interessa. Dovresti anche reindirizzare stderr, perché anche se sshd non sta aspettando la pipa corrispondente, dopo le sshduscite, la pipa verrà rotta e rsyncverrebbe uccisa se provasse a scrivere su stderr.

Così:

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

Confrontare:

$ 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

E:

$ 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


3

La -fbandiera per sshrisolvere il problema. Testato su:

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

Quando lo eseguo ssh localhost ./script, attende fino a quando non viene sleptvisualizzato. Con il -fflag, esce da echo $$_script__ende sleptsuccessivamente appare in background dopo che il sshcomando è tornato.


2

Questo è un problema noto del server OpenSSH, che è descritto e discusso in bugzilla upstream # 2071 . Nel bug, vengono proposte diverse soluzioni alternative nel lato OpenSSH, ma anche per lo script.

Se vuoi aspettare l'output degli script, dovresti aggiungere anche un waitprima exitdi scriptB.

Se non ti interessa l'output, usa alcune varianti di nohupe reindirizzamento IO per /dev/nullrisolvere il problema allo stesso modo.


1

Puoi provare questo. $!è la variabile shell predefinita che contiene l'ID del processo della pipeline / processo in background eseguita più di recente.

command1 &
lpid1=$!

command2 &
lpid2=$!

command3 &
lpid=$!

wait $lpid1  # waits for only the process with PID lpid1  to complete. 

È necessario utilizzare questo come per lo script utilizzando la exportvariabile ecc


1

B deve solo attendere i propri processi in background:

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

A quel punto potresti anche non eseguire il secondo rsync in background ed evitare di usarlo waitinteramente. Anche se sto indovinando che cosa intendeva fare l'OP era eseguire entrambi i rsyncprocessi in parallelo, il che significherebbe metterli in background entrambi (con &) e quindi utilizzare wait. In ogni caso, sono d'accordo che questo è il modo più semplice per risolvere il problema ed è quello che sceglierei in base alle informazioni nella domanda.
David Z,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.