Два окна, один и тот же пользователь, с подсказками bash. В окне типа 1:
$ mkfifo f; exec <f
Таким образом, теперь bash пытается прочитать из файлового дескриптора 0, который сопоставлен с именованным каналом f
. В окне типа 2:
$ echo ls > f
Теперь window-1 печатает ls, а затем оболочка умирает. Почему?
Следующий эксперимент: снова открыть окно-1 с помощью exec <f
. В окне типа 2:
$ exec 3>f
$ echo ls >&3
После первой строки выше, window-1 просыпается и печатает подсказку. Почему? После второй строки выше, window-1 печатает ls
вывод, и оболочка остается в живых. Почему? Фактически, теперь в window-2, echo ls > f
не закрывается оболочка window-1.
Ответ должен иметь отношение к существованию файлового дескриптора 3 из окна 2, ссылающегося на именованный канал ?!
file-descriptors
fifo
Fixee
источник
источник
exec <f
,bash
не пытается прочитать изf
его сначала пытается открыть его. Онopen()
не вернется, пока какой-нибудь процесс не сделает еще одно открытие в режиме записи в канал (в этот момент будет создан экземпляр канала, и оболочка будет читать входные данные из него).exec 3>f
запуска первая оболочка выдает приглашение. (Незначительный момент, вы имели в виду «в режиме записи » в своем комментарии?)Ответы:
Это связано с закрытием дескриптора файла.
В вашем первом примере
echo
записывает в свой стандартный поток вывода, который открывает оболочка для соединения с нимf
, и когда он завершается, его дескриптор закрывается (оболочкой). На принимающей стороне оболочка, которая считывает ввод из своего стандартного входного потока (подключенного кf
), читаетls
, запускаетсяls
и затем завершается из-за условия конца файла на своем стандартном вводе.Условие окончания файла возникает из-за того, что все пишущие в именованный канал (только один в этом примере) закрыли свой конец канала.
Во втором примере
exec 3>f
открывается дескриптор файла 3 для записиf
, а затемecho
записьls
в него. Теперь у оболочки есть дескриптор файла, а неecho
команда. Дескриптор остается открытым, пока вы не сделаетеexec 3>&-
. На принимающей стороне оболочка, которая читает входные данные из своего стандартного входного потока (подключенного кf
), читаетls
, запускается,ls
а затем ожидает дополнительного ввода (поскольку поток все еще открыт).Поток остается открытым, потому что все записывающие его (оболочка, via
exec 3>f
иecho
) не закрыли свой конец канала (exec 3>f
все еще действует).Я написал
echo
выше, как если бы это была внешняя команда. Скорее всего, он встроен в оболочку. Эффект тот же, тем не менее.источник
В этом нет ничего особенного: когда нет писателей в канал, он выглядит закрытым для читателей, то есть возвращает EOF при чтении и блоки при открытии.
Из справочной страницы Linux (
pipe(7)
но также смотритеfifo(7)
):Закрытие конца записи - это то, что неявно происходит в конце
echo ls >f
, и, как вы говорите, в другом случае файловый дескриптор остается открытым.источник
Прочитав два ответа от @Kusalananda и @ikkachu, я понял, что понимаю. В окне 1 оболочка ожидает чего-то, чтобы открыть конец записи канала и затем закрыть его. Как только конец записи открыт, оболочка в окне 1 печатает приглашение. Как только конец записи закрыт, оболочка получает EOF и умирает.
На стороне окна-2 мы имеем две ситуации , описанные в моем вопросе: в первой ситуации с
echo ls > f
, нет файлового дескриптора 3, поэтому мыecho
нерест, а егоstdin
иstdout
выглядеть следующим образом :Затем
echo
завершается, и оболочка закрывает оба дескриптора. Поскольку файловый дескриптор 1 закрыт и ссылаетсяf
, конец записиf
закрывается, и это приводит к EOF для window-1.Во второй ситуации мы запускаем
exec 3>f
нашу оболочку, заставляя оболочку принимать эту среду:Теперь мы запускаем
echo ls >& 3
и оболочка распределяет файловые дескрипторыecho
следующим образом:Затем оболочка закрывает три описанных выше дескриптора, включая
f
, ноf
все еще имеет ссылку на нее из самой оболочки. Это важное отличие. Закрывающий дескриптор 3 сexec 3>&-
закрывает последнюю открытую ссылку и вызывает EOF к окну-1, как заметил @Kusalananda.источник