(Баш) Сценарій A, чекайте сценарію B, але не його дочірнього процесу


9

Отже, у мене є scriptA, який робить:

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

ScriptB робить:

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

Мій бажаний результат - scriptA буде чекати, коли всі екземпляри scriptB закінчаться перед тим, як рухатися далі, що в даний час робить, однак він також чекає фонових rsyncs не так важливих речей. Це більші файли, на які я не хочу чекати.

Я прочитав різницю між nohup, disown і & і спробував різні комбінації, але я не отримую результату, який шукаю.

У цей момент я досить спотикався. Будь-яка допомога буде вдячна!

Відповіді:


15

Проблема тут полягає в тому, що він sshdчекає закінчення файлу в трубі, з якого він читає stdout команди (а не з більш жорсткої з певних причин, принаймні, з версією, яку я тестую) з. І фонове завдання успадковує fd до цієї труби.

Отже, щоб обійти це, перенаправляйте вихід цієї фонової rsyncкоманди на якийсь файл або /dev/nullякщо вам це не важливо. Ви також повинні перенаправити stderr, тому що навіть якщо sshd не чекає відповідної труби, після sshdвиходів труба буде зламана, тому rsyncвона буде вбита, якщо вона спробує записати на stderr.

Тому:

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

Порівняйте:

$ 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

І:

$ 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

4

Напишіть сценарій, який є батьком обох, тоді ви можете легко керувати обома . Альтернативно встановити канал зв'язку між двома каналами .

Щоб ігнорувати певні фонові завдання, ви можете зафіксувати PID ( $!це PID останнього фонового завдання) та wait $pidдочекатися завершення цього завдання.


3

-fПрапор sshвиправляє проблему. Тестовано на:

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

Коли я запускаю його ssh localhost ./script, він чекає, поки sleptз’явиться. З -fпрапором він вимикається в echo $$_script__endі sleptпізніше відображається на задньому плані після sshповернення команди.


2

Це відома проблема сервера OpenSSH, що описується та обговорюється у версії bugzilla №2071 . У помилці пропонується декілька обхідних шляхів або на стороні OpenSSH, але і для сценарію.

Якщо ви хочете зачекати на вихід скриптів, вам слід також додати waitдо exitцього scriptB.

Якщо ви не піклуєтесь про вихід, використовуйте певні зміни nohupта перенаправлення вводу-виводу, щоб /dev/nullвирішити проблему так само.


1

Ви можете спробувати це. $!є змінною оболонки за замовчуванням, яка містить ідентифікатор процесу останнього виконаного фонового конвеєра / процесу.

command1 &
lpid1=$!

command2 &
lpid2=$!

command3 &
lpid=$!

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

Вам потрібно використовувати це відповідно до вашого сценарію, використовуючи exportзмінну тощо


1

B просто потрібно дочекатися власних фонових процесів:

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

У цей момент ви можете просто не запускати другу rsync у фоновому режимі і уникати використання waitцілком. Хоча я припускаю , що ОП хотів зробити було запустити обидва rsyncпроцесу паралельно, що означало б їх фоновий і&) , а потім з допомогою wait. У будь-якому випадку я погоджуюся, що це найпростіший спосіб виправити проблему, і це той, який я обрав би, виходячи з інформації, яка міститься в питанні.
David Z
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.