Почему `while true; do echo y; done | true` умирает сам по себе, а `while true; do echo y | cat; done | true` — нет?

Почему `while true; do echo y; done | true` умирает сам по себе, а `while true; do echo y | cat; done | true` — нет?

Чтобы прояснить вопрос в заголовке, я понимаю, почему первый умирает. Я не понимаю, почему второй не умирает, просто для добавления a | catк телу цикла.

Также, возможно, связано,

while true; do echo y; done

умирает немедленно, когда я это делаю ^C, но убивая

while true; do echo y | cat; done

часто требуется ударить ^Cбольше одного раза. Иногда один раз срабатывает, иногда 2 или 3 раза срабатывает, а иногда мне нужно ^Cнекоторое время подержать, чтобы он умер.

Оба варианта поведения встречаются как в bash, так и в zsh, хотя ^Cв bash первое встречается реже.

Для обоих поведений это не ограничивается добавлением трубы в cat. | dd, | tee, и т.д. также вызывают их. Даже echo y | trueвызывает это. Кажется, это наличие любой трубы в теле цикла.

Почему наличие трубы в теле контура изменяет реакцию контура на сигналы?

решение1

В while true; do echo y; done | true, поскольку echoон встроен, у вас есть процесс подоболочки, который записывает y\nв цикле в канал.

При trueвозврате конец чтения этого канала закрывается, поэтому запись в конец записи приводит к SIGPIPEдоставке в процесс записи. Здесь это процесс подоболочки, который запускает цикл.

В while true; do echo y | cat; done | true, это , catкоторый записывает в канал. catобычно не встроен, и даже если бы он был, в оболочках, отличных от zsh и ksh, все компоненты каналов всегда запускаются в дочерних процессах.

Таким образом, здесь завершается только работающий процесс cat, а процесс подоболочки, который запускает цикл, продолжает выполнять другие catпроцессы, которые завершаются, как только они записывают данные y\nв свой stdout.

В ksh93/ksh2020, если вы это сделаете:

$ builtin cat
$ type cat
cat is a shell builtin
$ set -o pipefail
$ while true; do echo y | cat; done | true; kill -l "$?"
PIPE

На этот раз catвстроен и выполняется в том же процессе, что и цикл (как и catсамая правая команда в первой строке конвейера, а ksh не запускает ее в подоболочке), поэтому подоболочка выполняет trueвыход и kill -lподтверждает, что она была завершена сигналом SIGPIPE.

Связанный контент