Dois canais de entrada através de shuffling de descritor de arquivo e / dev / fd

3

Eu quero canalizar dois programas em um. Se o meu shell suportar, eu posso usar Substituição de processos . 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 do processo não existe em sh . Eu posso fazê-lo com portabilidade POSIX completa, criando um pipe nomeado , mas isso é complicado, pois requer encontrar um diretório para o FIFO e limpeza depois. Um bom compromisso prático é usar duas construções de pipe de shell e usar o embaralhamento de descritor de arquivo para mover um pipe para outro descritor de arquivo e 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 traço, bash, BusyBox sh, etc. mas não em ksh93 e mksh. Por quê?

$ 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
    
por Gilles 14.02.2016 / 00:59

1 resposta

3

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 (por exemplo, para um redirecionamento no exec builtin, depois de chamar dup2 para executar o redirecionamento, eles definem o FD_CLOEXEC flag on o 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 de dois canais de entrada (assumindo a existência de /dev/fd ) é executar 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 no pdksh / mksh e no ksh93r, mas não nas versões recentes do ksh (93s + 2008-01-31 ou 93u + 2012-08-01). Eu não entendo o que o ksh está fazendo lá.

    
por 14.02.2016 / 00:59