Comportamento de duplicação do descritor de arquivo

3

Eu tenho este arquivo:

1
2
3
4

Quando executo paste dessa maneira

paste - - <file

isso resulta

1       2
3       4

até agora tão boa, a entrada padrão (redirecionada de file ) é passada duas vezes para paste , portanto as linhas ímpares e pares são impressas em pares.

No entanto, quando isso é alterado para

paste - /dev/fd/0 <file

a saída se torna

1       1
2       2
3       3
4       4

paste parece estar abrindo file duas vezes (levando a duas entradas distintas na tabela de arquivos do kernel?), uma vez para o argumento - e mais uma vez para /dev/fd/0 .

Eu não sei explicar isso - se eu estiver interpretando isso - como /dev/fd/0 devem referenciar uma única entrada da tabela de arquivos do kernel, portanto, paste deve estar produzindo resultados idênticos ao caso anterior.

    
por iruvar 04.05.2017 / 17:28

1 resposta

5

Isso é específico para o Linux. Enquanto na maioria dos Unices, abrir /dev/fd/n é mais ou menos o mesmo que dup(n) (obter um descritor de arquivo para a mesma descrição do arquivo aberto como em fd n ), no Linux, /dev/fd/n é um link simbólico para o arquivo aberto no descritor de arquivo n .

Então, no Linux:

paste - /dev/fd/0 < file

é o mesmo que:

paste - file < file

(ou paste file file ).

Os dois fds (0 para - e o próprio obtido abrindo /dev/fd/0 ou file ), são independentes e possuem seu próprio cursor dentro do arquivo.

Você também notará que no Linux você não pode usar / dev / fd / n com sockets.

Geralmente no Linux, você só quer usar /dev/fd/n com pipes. Mas neste caso

cat file | paste - /dev/fd/0

(ou mudar para um sistema operacional não baseado em Linux) não ajudará muito. paste - - funciona porque paste sabe que é stdin nos dois casos. Mas não aqui, então ele vai ler um pedaço inteiro (em oposição a uma única linha) de - (fd 0 para o pipe), e então outro pedaço de / dev / fd / 0 (um fd independente para o mesmo pipe no Linux, mas se esses fds apontam para a mesma descrição do arquivo aberto ou não, não importa para um pipe). Ambos read() s lerão partes separadas do arquivo, mas várias linhas de cada vez.

Você precisaria dizer paste para ler um byte de cada vez para que ele não leia mais de uma linha de - antes de ler uma linha de /dev/fd/0 , o que você provavelmente não pode fazer sem recompilar . Você pode conseguir que paste leia seu stdin um byte de cada vez com stdbuf , mas provavelmente não /dev/fd/0 :

$ cat file | paste - /dev/fd/0
1
2
3
4
$ cat file | stdbuf -i1 paste - /dev/fd/0
1       2
        3
        4
    
por 04.05.2017 / 17:34