Фоновый процесс подоболочки странного поведения

Интересно, почему некоторые подобные команды bash ведут себя так же, как они.

У меня есть скрипт bash foo :

 #!/usr/bin/env bash while true do echo "reading" read data echo $data echo "stderr msg" >&2 sleep 1 done 

Это бесконечный цикл, который читает одну строку за раз из стандартного ввода и выводит ту же строку. У меня также есть bar сценариев bash:

 #!/usr/bin/env bash ./foo & 

Следующие команды были запущены в bash (v. 4.4.19) в терминале Ubuntu 18.04 (предположим, что скрипты находятся в рабочем каталоге):

1) ./foo &

  • Останавливается, когда он пытается прочитать из стандартного ввода, в соответствии с этим ответом .

  • Убивается, когда управляющий терминал убит, как и ожидалось.

2) (./foo &)

  • Похоже, что он автоматически непрерывно запитывается новым вводом от stdin. Разве это не должно прекратиться при попытке чтения со стандартного ввода? Что бы оно ни получало, оно не отображается при отражении, поэтому я предполагаю, что это EOF-персонажи.

  • Продолжает работать даже после того, как управляющий терминал убит. Если посмотреть на вывод ps , управляющий терминал изменится с pts / x на?. Как это произошло без использования disown или nohup ? (Однако после уничтожения изначально управляющего терминала он выдает «ошибку записи: ошибка ввода / вывода» при каждой записи, что, как я полагаю, связано с тем, что его стандартный вывод был привязан к теперь закрытому терминалу.

3) bash -c "./foo &"

Кажется, ведет себя точно так же, как 2).

4) ./bar

Кажется, ведет себя точно так же, как 2) и 3).

5) Добавление bash -c "~/foo" (no & ) в качестве запускаемого приложения

Ведет себя аналогично 2), 3) и 4), с отличиями:

  • Его управляющим терминалом является настольный компьютер tty x .
  • Вы не можете (не так ли?) Убить его контролирующий терминал.

Ни одно из этих различий не кажется мне странным, просто тот факт, что он постоянно подпитывается новыми данными.

Я предполагаю, что 2) – 5) все используют своего рода подоболочку, чей stdin перенаправляется на что-то вроде /dev/null , хотя я очень не уверен и ищу более точный ответ.

Команды, запускаемые с & в оболочке без включенного управления заданиями (например, в скрипте или (...) подоболочке), имеют свой stdin, перенаправленный из /dev/null а SIGINT и SIGQUIT установлены в SIG_IGN . Из стандарта susv4:

Если управление заданиями отключено (см. set , -m ), стандартный ввод для асинхронного списка перед выполнением любых явных перенаправлений должен считаться назначенным файлу, имеющему те же свойства, что и /dev/null . Этого не должно быть, если включен контроль заданий. Во всех случаях явное redirect стандартного ввода должно переопределять это действие.

Смотрите также это и это .

Это неправда, что ваш скрипт ./foo «непрерывно ./foo » данные – он получает EOF при попытке чтения из /dev/null – вы должны проверить состояние выхода read .

Ваши подчиненные оболочки не являются интерактивными; автоматически убиваются только интерактивные оболочки.