Как описано в заголовке, я пытаюсь запустить программу из сценария bash, но она останавливается, когда я запускаю сценарий в фоновом режиме. Однако это происходит только в том случае, когда я перенаправляю его стандартный ввод на именованный канал и оставляю канал открытым из того же сценария.
Вот минимальное воспроизведение поведения:
В foo.sh
у меня есть:
#!/bin/bash
while true
do
echo "Running"
sleep 1
done
В bar.sh
у меня есть:
#!/bin/bash
rm -f pipe
mkfifo pipe
./foo.sh < pipe & # Let's say foo.sh has PID 42
cat > pipe
В оболочке я запускаю ./bar.sh
, который, как и ожидалось, постоянно печатает «Выполняется». Потом ставлю фон bar.sh
и он перестает печатать. Если я запущу kill -CONT 42
, он снова начнет печатать.
Однако, если я не перенаправляю стандартный ввод в канал (т. е. заменяю ./foo.sh < pipe &
просто на ./foo.sh &
), когда я фонирую bar.sh
, печать не прекращается.
Может ли кто-нибудь объяснить мне эту разницу в поведении и, если возможно, объяснить, как я могу предотвратить остановку foo.sh
, когда он получает стандартный ввод из именованного канала?
@DavidC.Rankin, они кажутся похожими, но все ответы, похоже, описывают остановку, вызванную попыткой фонового процесса прочитать данные с терминала своего сеанса. Это не то, что происходит здесь с ОП foo.sh
. Его стандартный ввод не подключен к терминалу, и он все равно не пытается читать со стандартного ввода.
По крайней мере, не напрямую.
Я был бы склонен сказать, что foo.sh
останавливается, потому что он находится в той же группе процессов, что и bar.sh
(что и было в моих тестах), но это не объясняет зависимость от того, подключен ли его stdin
к каналу или к терминалу, который я могу воспроизвести. Однако отмечу, что я не воспроизвожу возможность продолжения foo.sh
после остановки, кроме как возвращая всю работу на передний план.
cat > pipe
пытается прочитать со стандартного ввода и записать в канал.
Я думаю, что Бармар в своем ответе уловил последовательность событий, которая привела к остановке фоновой работы. Я знаю, что сталкивался с этой проблемой не раз. Любой ввод-вывод из фонового процесса, который влияет на любой из стандартных потоков, является неприятным. Мне придется протестировать, но я бы обязательно попробовал перенаправить на другой файловый дескриптор и посмотреть, повлияет ли это на канал. Я также должен признать, что никогда не занимался этой проблемой. В общем, спеша, я просто обошел это другим способом..... люди....
Извините, @JohnBollinger прав, я не могу продолжить foo.sh
, не выведя всю работу на передний план. Это было из предыдущей версии скрипта, который я тестировал, где у меня было cat pipe &
вместо ./foo.sh < pipe &
, и в этом случае я мог продолжить остановленную программу cat. Я отредактировал вопрос, чтобы отразить это.
cat > pipe
пытается прочитать со стандартного ввода, поэтому он останавливается, когда работает в фоновом режиме.
Причина, по которой этого не происходит, если вы не перенаправляете ввод foo.sh
в канал, заключается в том, что оболочка блокируется при попытке открыть канал для записи. Это не удастся, пока другой процесс не откроет его для чтения, и он не запустится cat
, пока не откроет канал.
Когда я воспроизвожу ошибку, ps
показывает, что и foo.sh
, и bar.sh
находятся в состоянии T
(остановлено):
PID TTY STAT TIME COMMAND
1888904 pts/1 T 0:00 /bin/bash ./bar.sh
1888907 pts/1 T 0:00 /bin/bash ./foo.sh
1888908 pts/1 T 0:00 cat
1888924 pts/1 T 0:00 sleep 1
Таким образом, похоже, что останавливается вся группа процессов, а не только процесс cat
.
Симптомы в MacOS отличаются от Linux. На Mac я получаю следующую ошибку, когда ставлю bar.sh
в фоновом режиме:
cat: stdin: Interrupted system call
и Running
продолжает печатать. Не знаю, связано ли это с различиями ОС или с более старой версией bash
.
Это имеет смысл, но ответ был бы более полным, если бы объяснялось, почему foo.sh
также останавливается, когда bar.sh
пытается прочитать стандартный ввод в фоновом режиме.
Ага, ок, я понимаю, о чем вы говорите: cat > pipe
не запускается, пока не откроется конец чтения, но я не понимаю, почему foo.sh
перестает работать, как только это происходит: если я не перенаправляю стандартный ввод foo.sh
в канал, а затем фон bar.sh
, он продолжает печатать, пока я не запускаю cat pipe
в другой оболочке, чтобы открыть конец чтения. Почему foo.sh
не продолжает работу в фоновом режиме, хотя cat > pipe
остановлен? Я чувствую, что упускаю здесь что-то фундаментальное в сфере фоновых профессий. Не могли бы вы уточнить первую часть вашего ответа?
Я не могу воспроизвести проблему foo.sh
остановки.
@Бармар, вот последовательность событий, которая заставляет меня остановиться. Содержимое foo.sh
такое же, как и мой исходный вопрос, а в bar.sh
строка ./foo.sh < pipe &
заменена только на ./foo.sh &
. В оболочке 1 я запускаю ./bar.sh
, затем фонирую его. На данный момент foo.sh
все еще работает. Затем в оболочке 2 я запускаю cat pipe
, чтобы открыть конец чтения. В этот момент foo.sh
прекращает печать.
Я повторю попытку в Linux, чтобы посмотреть, отличается ли он от MacOS.
Хорошо, я понимаю вашу неудачу в Linux. ps
показывает, что все процессы находятся в состоянии T
.
Я обновил ответ.
Вероятно, дубликат процесса Linux в фоновом режиме — «Остановлено» в заданиях? и видите фоновая работа продолжает останавливаться