Два входных канала через перетасовку файловых дескрипторов и /dev/fd

Два входных канала через перетасовку файловых дескрипторов и /dev/fd

Я хочу объединить две программы в одну. Если моя оболочка это поддерживает, я могу использоватьПроцесс замены. Например, чтобы перечислить общие строки двух файлов в разном порядке, я могу использовать

comm -12 <(sort a) <(sort b)

Однако подстановка процесса не существует в простом виде sh. Я могу сделать это с полной переносимостью POSIX, создавименованный канал, но это обременительно, так как требует поиска каталога для FIFO и последующей очистки. Хорошим практическим компромиссом является использование двух конструкций конвейера оболочки и использование перетасовки дескрипторов файлов для перемещения одного конвейера в другой дескриптор файлов, а затем использование /dev/fdдля обозначения конвейера, что работает в большинстве вариантов Unix:

sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }

Это работает в dash, bash, BusyBox sh и т. д., но не в ksh93 и mksh. Почему?

$ mksh -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
$ ksh93 -c 'sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/3; }'
comm: /dev/fd/0: No such device or address

решение1

В отличие от перенаправлений в других командах, перенаправления во execвстроенной команде могут быть закрыты, когда оболочка выполняет внешнюю программу.POSIX допускает оба варианта поведения. Ksh (как ATT ksh, так и pdksh и mksh) закрывают эти дескрипторы, когда выполняют внешнюю утилиту (т. е. для перенаправления на execвстроенную утилиту, после вызова dup2для выполнения перенаправления, они устанавливают FD_CLOEXECфлаг на новый дескриптор). Оболочка Bourne, dash, bash, zsh и BusyBox sh обрабатывают это перенаправление как любое другое перенаправление.

Более переносимым решением проблемы двух входных каналов (предполагая существование /dev/fd) является выполнение еще одного перенаправления для команды, которая считывает входные данные, перемещая файловый дескриптор на новый. Это дополнительное перенаправление не устанавливает флаг close-on-exec для нового дескриптора.

sort a | { exec 3<&0; sort b | comm -12 /dev/fd/0 /dev/fd/4 4<&3; }

Это работает в pdksh/mksh и ksh93r, но не в последних версиях ksh (93s+ 2008-01-31 или 93u+ 2012-08-01). Я не понимаю, что там делает ksh.

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