Почему моя программа, запущенная из сценария bash, останавливается, когда сценарий находится в фоновом режиме, но только тогда, когда он получает стандартный ввод из именованного канала?

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

John Bollinger 04.09.2024 13:19

По крайней мере, не напрямую.

John Bollinger 04.09.2024 13:36

Я был бы склонен сказать, что foo.sh останавливается, потому что он находится в той же группе процессов, что и bar.sh (что и было в моих тестах), но это не объясняет зависимость от того, подключен ли его stdin к каналу или к терминалу, который я могу воспроизвести. Однако отмечу, что я не воспроизвожу возможность продолжения foo.sh после остановки, кроме как возвращая всю работу на передний план.

John Bollinger 04.09.2024 13:47
cat > pipe пытается прочитать со стандартного ввода и записать в канал.
Barmar 04.09.2024 17:52

Я думаю, что Бармар в своем ответе уловил последовательность событий, которая привела к остановке фоновой работы. Я знаю, что сталкивался с этой проблемой не раз. Любой ввод-вывод из фонового процесса, который влияет на любой из стандартных потоков, является неприятным. Мне придется протестировать, но я бы обязательно попробовал перенаправить на другой файловый дескриптор и посмотреть, повлияет ли это на канал. Я также должен признать, что никогда не занимался этой проблемой. В общем, спеша, я просто обошел это другим способом..... люди....

David C. Rankin 04.09.2024 21:38

Извините, @JohnBollinger прав, я не могу продолжить foo.sh, не выведя всю работу на передний план. Это было из предыдущей версии скрипта, который я тестировал, где у меня было cat pipe & вместо ./foo.sh < pipe &, и в этом случае я мог продолжить остановленную программу cat. Я отредактировал вопрос, чтобы отразить это.

Eclogite 04.09.2024 22:22
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
7
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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 пытается прочитать стандартный ввод в фоновом режиме.

John Bollinger 04.09.2024 22:44

Ага, ок, я понимаю, о чем вы говорите: cat > pipe не запускается, пока не откроется конец чтения, но я не понимаю, почему foo.sh перестает работать, как только это происходит: если я не перенаправляю стандартный ввод foo.sh в канал, а затем фон bar.sh, он продолжает печатать, пока я не запускаю cat pipe в другой оболочке, чтобы открыть конец чтения. Почему foo.sh не продолжает работу в фоновом режиме, хотя cat > pipe остановлен? Я чувствую, что упускаю здесь что-то фундаментальное в сфере фоновых профессий. Не могли бы вы уточнить первую часть вашего ответа?

Eclogite 04.09.2024 22:47

Я не могу воспроизвести проблему foo.sh остановки.

Barmar 04.09.2024 22:47

@Бармар, вот последовательность событий, которая заставляет меня остановиться. Содержимое foo.sh такое же, как и мой исходный вопрос, а в bar.sh строка ./foo.sh < pipe & заменена только на ./foo.sh &. В оболочке 1 я запускаю ./bar.sh, затем фонирую его. На данный момент foo.sh все еще работает. Затем в оболочке 2 я запускаю cat pipe, чтобы открыть конец чтения. В этот момент foo.sh прекращает печать.

Eclogite 04.09.2024 22:49

Я повторю попытку в Linux, чтобы посмотреть, отличается ли он от MacOS.

Barmar 04.09.2024 22:50

Хорошо, я понимаю вашу неудачу в Linux. ps показывает, что все процессы находятся в состоянии T.

Barmar 04.09.2024 22:52

Я обновил ответ.

Barmar 04.09.2024 22:54

Другие вопросы по теме

Когда grep ищет шаблоны в файле с кавычками и/или без кавычек в bash?
Как извлечь столбцы из файла CSV, обработать и создать файл CSV на основе результата извлечения и обработки?
Скрипт Bash, который принимает несколько аргументов пути и проверяет, можно ли там успешно создать файлы
Почему bash не завершает выполнение сценария после ошибки внутри скобок?
Как запустить эмулятор терминала во время работы оболочки?
Как мне отслеживать и уничтожать все процессы, порожденные запуском сценария, не зная имен подпроцессов?
Bash: медленнее использовать zcat по сравнению с cat+zcat или cat+pv+zcat
Как передать переменную оболочки, возвращаемую из Pythonscript, в другую оболочку для запуска другого Pythonscript в правиле Makefile?
Правильное использование кавычек при подстановке команд – как?
Синтаксическая ошибка рядом с токеном в сценарии bash, инициализирующем conda