(bash) Skrypt A, poczekaj na skrypt B, ale nie na jego proces potomny


9

Mam więc skrypt A, który:

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

ScriptB wykonuje:

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

Moim pożądanym wynikiem jest skrypt A, zanim przejdzie dalej, zaczeka na zakończenie wszystkich wystąpień skryptu B, ale obecnie również czeka na synchronizację w tle nie tak ważnych rzeczy. To są większe pliki, na które nie chcę czekać.

Przeczytałem Różnicę między nohup, disown i & i wypróbowałem różne kombinacje, ale nie otrzymuję rezultatu, którego szukam.

W tym momencie jestem dość zakłopotany. Każda pomoc będzie mile widziana!

Odpowiedzi:


15

Problem polega na tym, że sshdczeka na końcu pliku na potoku, z którego odczytuje stdout polecenia (z jakiegoś powodu nie stderr, przynajmniej z wersją, na której testuję). A zadanie w tle dziedziczy fd do tej rury.

Aby obejść ten problem, przekieruj wyjście tego rsyncpolecenia w tle do jakiegoś pliku lub /dev/nulljeśli go nie obchodzi. Powinieneś także przekierować stderr, ponieważ nawet jeśli sshd nie czeka na odpowiednią potok, po sshdwyjściu potok zostanie uszkodzony, więc rsynczostałby zabity, jeśli spróbuje napisać na stderr.

Więc:

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

Porównać:

$ 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

I:

$ 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

-fFlagę sshrozwiązuje problem. Testowane na:

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

Kiedy go uruchomię ssh localhost ./script, czeka, aż się sleptpojawi. Z -fflagą wychodzi na, echo $$_script__enda sleptpóźniej pojawia się w tle po sshpowrocie polecenia.


2

Jest to znany problem serwera OpenSSH, który został opisany i omówiony w poprzedniej Bugzilli # 2071 . W błędzie zaproponowano kilka obejść po stronie OpenSSH, ale także dla skryptu.

Jeśli chcesz poczekać na dane wyjściowe skryptów, powinieneś dodać również waitprzed exitnimi scriptB.

Jeśli nie zależy ci na danych wyjściowych, skorzystaj z pewnej odmiany nohupi przekierowania IO do /dev/null, co rozwiąże problem w ten sam sposób.


1

Możesz tego spróbować. $!jest domyślną zmienną powłoki, która zawiera identyfikator procesu ostatnio wykonywanego potoku / procesu w tle.

command1 &
lpid1=$!

command2 &
lpid2=$!

command3 &
lpid=$!

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

Musisz użyć tego zgodnie ze skryptem, używając exportzmiennej itp


1

B musi tylko poczekać na swoje własne procesy w tle:

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

W tym momencie równie dobrze możesz nie uruchamiać drugiego rsync w tle i unikać używania waitcałkowicie. Chociaż zgaduję, że OP miał na myśli rsyncrównoległe uruchomienie obu procesów, co oznaczałoby, że oba z nich byłyby w tle (z &), a następnie użyte wait. W każdym razie zgadzam się, że jest to najprostszy sposób na rozwiązanie problemu i wybieram go na podstawie informacji zawartych w pytaniu.
David Z
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.