Согласно документации, bash ожидает завершения всех команд в конвейере, прежде чем продолжить
Оболочка ожидает завершения всех команд в конвейере, прежде чем вернуть значение.
Так почему же команда yes | true
завершается немедленно? Разве yes
цикл не должен вечно вызывать конвейер?
И подзапрос: согласно спецификации POSIX , конвейеры оболочки могут выбрать либо возврат после завершения последней команды, либо ожидание завершения всех команд. Разве обычные оболочки имеют различное поведение в этом смысле? Есть ли снаряды, где yes | true
будут петли вечно?
yes | tee >(true) >/dev/null
будет делать, как вы ожидаете, между прочим, такtee
продолжается до тех пор, пока все писатели не умрут, поэтомуtrue
выход не нарушит его полностью.true
это в основном{return 0;}
программа, поэтому я не ожидаю, что она будет работать долго, не говоря уже о вечности.Ответы:
При
true
выходе сторона чтения канала закрывается, ноyes
продолжает пытаться выполнить запись в сторону записи. Это условие называется «сломанный канал», и оно заставляет ядро отправлятьSIGPIPE
сигналyes
. Посколькуyes
ничего особенного в этом сигнале не делается, он будет убит. Если он проигнорирует сигнал, егоwrite
вызов завершится ошибкой с кодом ошибкиEPIPE
. Программы, которые делают это, должны быть готовы заметитьEPIPE
и прекратить писать, иначе они пойдут в бесконечный цикл.Если вы сделаете
strace yes | true
1, вы увидите, что ядро готовится к обеим возможностям:strace
наблюдает за событиями через API отладчика, который сначала сообщает ему о возвращении системного вызова с ошибкой, а затем о сигнале. Сyes
точки зрения, однако, сигнал происходит первым. (Технически, сигнал доставляется после того, как ядро вернуло управление в пространство пользователя, но до того, как будут выполнены какие-либо машинные инструкции, поэтомуwrite
функция «обертка» в библиотеке C не получает возможности установитьerrno
и вернуться в приложение.)1 К сожалению,
strace
это специфично для Linux. В большинстве современных Unix-ов есть какая-то команда, которая делает что-то похожее, но часто имеет другое имя, вероятно, она не декодирует аргументы системного вызова так же тщательно, а иногда она работает только для root.источник
yes
связано с трубой.yes
получение SIGPIPE, поскольку FD, на который он пишет, не подключен к каналу.yes >/dev/null
как цикл навсегда. Он не демонстрирует ничего о конвейерах, что также не относится к простым командам (как отмечает Том, ожидающий завершения, это относится и к простым командам).write()
(функция в libc) не возвращается (после этого передает управление на ПК) до тех пор, пока обработчик сигнала запущен, но поскольку обработчик сигнала завершает программу, управление никогда не передается и, следовательно,write()
никогда не возвращается. Да, это реализовано в ядре с помощьюxxx_write()
возврата некоторой функции-EPIPE
, но мы отлаживаем программу пользовательского пространства и не заинтересованы в этом.Маловероятно, так как
yes
команда использует канал, и он потерпит неудачу, когда канал будет разорван.sleep
с другой стороны, не использует трубу, поэтому:будет работать как минимум 100000000 секунд.
источник
true
находится встроенная команда. Это относится и к последним версиямBourne Shell
,ksh93
,zsh
. Если вы нажмете^Z
во время выполнения такой команды, это приостановит режим сна, и оболочка никогда не сможет восстановиться без внешней помощи.sbrk()
. Портативная и поддерживаемая версия находится в комплекте инструментов schily, и @Charles Duffy уже обнаружил место для информации ;-)bsh
(Berthold Shell из VBERTOS, версия UNOS с расширенной виртуальной памятью - первый клон UNIX). Bsh действительно получил много возможностей csh в 1984 и 1985 годах, но механизм псевдонимов в UNOS был лучше, чем в csh в 1980 году. Другие новые функции Bourne Shell - от POSIX, чтобы позволить ему приблизиться к соответствию POSIX.