1

Я пытаюсь зациклить, пока не завершится фоновый процесс (запущенный ранее в скрипте). Легко воспроизводимый контрольный пример:

ping -c 10 localhost &>/dev/null &

В командной строке я могу выполнить цикл while [[ -n $(jobs) ]] (в то время как $(jobs) не равно нулю).

$ 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

Однако те же две строки в сценарии будут продолжать печататься . пока я не нажму 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 не работает должным образом.

3 ответа3

2

Если я понимаю вашу проблему, ваши 2 строки не будут останавливаться в сценарии.

Вот что я сделал в своем:

ping -c 5 google.com &>/dev/null &
while [[ -n $(jobs -r) ]]; do echo -n "."; sleep 1; done

jobs -r проверяет запущенные процессы, и вызов моего сценария работает, как и ожидалось, сценарий останавливается, когда выполняется ping.

РЕДАКТИРОВАТЬ: Я думаю, что в сценарии родительский процесс известен как запущенный процесс, и поэтому jobs продолжают думать, что есть запущенный процесс. Это гипотеза

Это ответ? (или, может быть, я действительно не понимаю, что вы имеете в виду, мой плохой английский может быть проблемой ...)

1

Всякий раз, когда у вас возникают подобные проблемы, вы всегда должны пытаться распечатать свои переменные, чтобы понять, что происходит. В этом случае 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, если кому-то интересно.

0

Вы можете использовать команду wait которая ожидает остановки фоновых заданий

Пример:

$ ping -c 10 localhost &>/dev/null &
[29787]
$ wait
[1]+  Done ping -c 10 localhost &>/dev/null

Команда ожидания блокируется, и когда ping завершается, приглашение сбрасывается, а затем печатается сообщение.

Вы можете использовать это с несколькими командами:

$ 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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .