В zsh разница между cat <(cat) и cat | кошка против кошки = (кошка)?

18

Я ожидал cat <(cat)и cat | catсделать то же самое: скопировать строки из стандартного ввода в стандартный вывод. Насколько я понимаю, оба выполняли бы catв подоболочке, перенаправляли catstdout подоболочки во временный именованный канал, а затем выполняли другой catв текущей оболочке с его stdin, перенаправленным в канал.

Вместо этого cat <(cat)позволяет мне печатать на моем терминале, но ни одна из входных строк не копируется и ^Dне дает сигнал EOF; cat | catработает как и ожидалось.

В качестве дальнейшего эксперимента я проверил, cat =(cat)есть ли схожие трудности cat <(cat), но все работает, как я и ожидал: все stdin вплоть до a ^Dкопируются в stdout за один раз.

Может кто-нибудь помочь мне понять, что Zsh делает под капотом?

Алан О'Доннелл
источник

Ответы:

23
  1. a | bсоединяется STDOUTс aи STDINот bпросто с помощью dup/dup2. Обе команды выполняются параллельно.

  2. a =(b)заменяет аргумент на aвременным именем файла. bбудет выполнен до того, aкак временный файл должен быть создан, прежде чем он может быть переданa

  3. a <(b)заменяет аргумент на aименованным каналом. aи bработать параллельно. Теперь это немного усложняется:

    bнаходится в фоновом режиме и не может читать с терминала. Вы можете проверить это самостоятельно, используя strace -p $PIDдля присоединения к вашему второму процессу cat, чтобы увидеть процесс.

    aтем временем пытается читать из именованного канала, но не может читать ничего, как bне может читать.

    • Это означает, что у вас в основном тупик, когда вы aпытаетесь читать, bно bне можете читать STDINи не можете писать вa

Больше информации о фоновом процессе и терминале от man bash :

Чтобы облегчить реализацию пользовательского интерфейса для управления заданиями, операционная система поддерживает понятие текущего идентификатора группы процессов терминала . Члены этой группы процессов (процессы, чей идентификатор группы процессов равен текущему идентификатору группы процессов терминала) получают сигналы, генерируемые клавиатурой, такие как SIGINT . Эти процессы, как говорят, находятся на переднем плане . Фонпроцессы - это те, чей идентификатор группы процессов отличается от терминала; такие процессы неуязвимы для сигналов, генерируемых клавиатурой. Только процессам переднего плана разрешено чтение или, если пользователь указывает это с помощью stty tostop, запись в терминал. Фоновые процессы, которые пытаются прочитать (записать, когда действует stty tostop) с терминала, посылают сигнал SIGTTIN (SIGTTOU) драйвером терминала ядра, который, если не перехватывается, приостанавливает процесс.

Ульрих Дангел
источник
Отлично, спасибо - это многое прояснило!
Алан О'Доннелл
1
Обратите внимание, что, когда он не интерактивен, zsh перенаправляет стандартный ввод фоновых команд (включая команды in <(cmd)) на /dev/null, поэтому поведение отличается ( zsh -c 'cat <(cat)'немедленно возвращается и ничего не выводит).
Стефан Шазелас