%20%D0%BD%D0%B5%20%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0%D0%B5%D1%82%20%D0%B2%20%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B5.png)
Я пытаюсь зациклить, пока фоновый процесс (запущенный ранее в скрипте) не завершится. Легко воспроизводимый тестовый случай:
ping -c 10 localhost &>/dev/null &
В командной строке я могу выполнить цикл while [[ -n $(jobs) ]]
(пока $(jobs)
не null).
$ ping -c 10 localhost &>/dev/null &
[1] 19078
$ while [[ -n $(jobs) ]]; do echo -n .; sleep 1; done
.........[1]+ Done ping -c 5 localhost &> /dev/null
Однако те же две строки в скрипте будут продолжать печатать .
s до тех пор, пока я не нажму Ctrl-C
.
Странно, но если я вызываю jobs
внутри цикла, скрипт завершается, как и ожидалось.
$ ./background-ping.sh
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Running ping -c 5 localhost &> /dev/null &
.[1]+ Done ping -c 5 localhost &> /dev/null
Я знаю, что существуют и другие способы проверить, завершено ли фоновое задание (например, проверка /proc
), но я хочу знать, почему проверка jobs
не работает так, как ожидалось.
решение1
Если я правильно понял вашу проблему, ваши 2 строки не остановятся в сценарии.
Вот что я сделал в своем:
ping -c 5 google.com &>/dev/null &
while [[ -n $(jobs -r) ]]; do echo -n "."; sleep 1; done
jobs -r
проверяет запущенные процессы, и вызов моего скрипта работает как и ожидалось, скрипт останавливается после завершения ping.
EDIT: Я думаю, что в скрипте родительский процесс известен как запущенный процесс, и поэтому jobs
продолжайте думать, что есть запущенный процесс. Это гипотеза
Это ответ? (или, может быть, я действительно не понимаю, что вы имеете в виду, проблема может быть в моем плохом английском...)
решение2
Всякий раз, когда у вас возникают такие проблемы, вы всегда должны пытаться распечатать свои переменные, чтобы понимать, что происходит. В этом случае jobs
также возвращает завершенные задания. Если вы запустите это:
ping -c 5 localhost &>/dev/null &
while [[ -n $(jobs | tee -a temp) ]]; do
echo -n .;
sleep 1;
done
Вы увидите следующий вывод temp
:
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Running ping -c 5 localhost &> /dev/null &
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[1]+ Done ping -c 5 localhost &> /dev/null
[...]
Итак, вывод jobs
здесь никогда не бывает пустым. Даже когда работа завершена, jobs
все равно возвращает Done
сообщение. Вот почему решение Metal3d с использованием jobs -r
сработало.
Что еще более запутанно, так это то, почему запуск jobs
внутри цикла заставляет его работать правильно. Ответ будет как-то связан с тем фактом, что он while [[ -n $(jobs) ]]
запускается jobs
в отдельной подоболочке, но я не уверен в деталях. У меня естьразместил вопрособ этом на U&L, если кому-то интересно.
решение3
Вы можете использовать wait
команду, которая ждет остановки фоновых заданий.
Пример:
$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+ Done ping -c 10 localhost &>/dev/null
Команда wait блокируется, а по ping
завершении отпускается, после чего выводится сообщение.
Вы можете использовать is с несколькими командами:
$ ping -c 5 localhost &>/dev/null & ping -c 5 facebook.com &>/dev/null &
[1] 29867
[2] 29868
$ wait
[1]- Done ping -c 5 localhost &>/dev/null
[2]+ Done ping -c 5 facebook.com &>/dev/null