Как описано в заголовке, я пытаюсь запустить программу из сценария 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 в фоновом режиме — «Остановлено» в заданиях? и видите фоновая работа продолжает останавливаться