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/fd
para 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 exec
builtin 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 exec
builtin, após chamar dup2
para realizar o redirecionamento, eles definem o FD_CLOEXEC
sinalizador 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á.