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