Dois canais de entrada por meio de embaralhamento do descritor de arquivo e /dev/fd

Dois canais de entrada por meio de embaralhamento do descritor de arquivo e /dev/fd

Quero canalizar dois programas em um. Se meu shell suportar, posso usarSubstituição de processo. Por exemplo, para listar as linhas comuns de dois arquivos em ordem indiferente, posso usar

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

No entanto, a substituição de processos não existe em plain sh. Posso fazer isso com portabilidade POSIX total criando umtubo nomeado, mas isso é complicado, pois requer encontrar um diretório para o FIFO e limpá-lo posteriormente. Um bom compromisso prático é usar duas construções de shell pipe e usar o embaralhamento do descritor de arquivo para mover um pipe para outro descritor de arquivo e, em seguida, usar /dev/fdpara designar o pipe, que funciona na maioria das variantes do Unix:

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

Isso funciona em dash, bash, BusyBox sh, etc., mas não em ksh93 e mksh. Por que?

$ 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

Responder1

Ao contrário dos redirecionamentos em outros comandos, os redirecionamentos no execbuiltin podem ser fechados quando o shell executa um programa externo.POSIX permite ambos os comportamentos. Ksh (ambos ATT ksh, e pdksh e mksh) fecham esses descritores quando executam um utilitário externo (ou seja, para um redirecionamento no execbuiltin, após chamar dup2para realizar o redirecionamento, eles definem o FD_CLOEXECsinalizador no novo descritor). O shell Bourne, dash, bash, zsh e BusyBox sh tratam esse redirecionamento como qualquer outro redirecionamento.

Uma solução mais portátil para o problema dos dois tubos de entrada (assumindo a existência de /dev/fd) é realizar outro redirecionamento no comando que lê a entrada, movendo o descritor de arquivo para um novo. Esse redirecionamento extra não define o sinalizador close-on-exec no novo descritor.

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

Isso funciona em pdksh/mksh e em ksh93r, mas não em versões recentes do ksh (93s+ 31/01/2008 ou 93u+ 01/08/2012). Eu não entendo o que ksh está fazendo lá.

informação relacionada