No
./binary < file
binary
stdin é o arquivo aberto no modo somente leitura. Observe que bash
ele não lê o arquivo, apenas o abre para leitura no descritor de arquivo 0 (stdin) do processo em que ele é executado binary
.
No:
./binary << EOF
test
EOF
Dependendo do shell, binary
o stdin será um arquivo temporário excluído (AT&T ksh, zsh, bash ...) que contenha test\n
como colocado ali pelo shell ou pela extremidade de leitura de um pipe ( dash
, yash
; e o shell grava test\n
em paralelo na outra extremidade do tubo). No seu caso, se você estiver usando bash
, seria um arquivo temporário.
No:
cat file | ./binary
Dependendo do shell, binary
o stdin será a extremidade de leitura de um tubo ou a extremidade de um par de soquetes em que a direção de gravação foi desativada (ksh93) e cat
está gravando o conteúdo da file
outra extremidade.
Quando stdin é um arquivo regular (temporário ou não), ele pode ser procurado. binary
pode ir para o início ou o fim, retroceder, etc. Também pode mapeá-lo, fazer alguns ioctl()s
como FIEMAP / FIBMAP (se usar em <>
vez de <
, poderá truncar / fazer furos nele, etc.).
pares de tubos e soquetes, por outro lado, são um meio de comunicação entre processos, não há muito o binary
que fazer além read
dos dados (embora também existam algumas operações, como alguns ioctl()
s específicos de um tubo, que eles poderiam fazer neles e não em arquivos regulares) .
Na maioria das vezes, é a capacidade que faltava para seek
que faz com que aplicativos para falhar / reclamar quando se trabalha com tubos, mas poderia ser qualquer uma das outras chamadas de sistema que são válidas em arquivos regulares, mas não em diferentes tipos de arquivos (como mmap()
, ftruncate()
, fallocate()
) . No Linux, também há uma grande diferença de comportamento quando você abre /dev/stdin
enquanto o fd 0 está em um pipe ou em um arquivo regular.
Existem muitos comandos por aí que só podem lidar com arquivos pesquisáveis , mas quando esse é o caso, geralmente não é para os arquivos abertos em seu stdin.
$ unzip -l file.zip
Archive: file.zip
Length Date Time Name
--------- ---------- ----- ----
11 2016-12-21 14:43 file
--------- -------
11 1 file
$ unzip -l <(cat file.zip)
# more or less the same as cat file.zip | unzip -l /dev/stdin
Archive: /proc/self/fd/11
End-of-central-directory signature not found. Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. In the
latter case the central directory and zipfile comment will be found on
the last disk(s) of this archive.
unzip: cannot find zipfile directory in one of /proc/self/fd/11 or
/proc/self/fd/11.zip, and cannot find /proc/self/fd/11.ZIP, period.
unzip
precisa ler o índice armazenado no final do arquivo e, em seguida, procurar dentro do arquivo para ler os membros do arquivo. Mas aqui, o arquivo (regular no primeiro caso, canal no segundo) é fornecido como argumento de caminho unzip
e o unzip
abre por si próprio (normalmente em fd diferente de 0) em vez de herdar um fd já aberto pelo pai. Ele não lê arquivos zip de seu stdin. stdin é usado principalmente para interação do usuário.
Se você executar o binary
seu sem redirecionamento no prompt de um shell interativo em execução em um emulador de terminal, binary
o stdin será herdado de seu pai, o shell, que por sua vez o herdará de seu pai, o emulador de terminal e será um dispositivo pty aberto no modo de leitura + gravação (algo como /dev/pts/n
).
Esses dispositivos também não são procuráveis. Portanto, se binary
funcionar bem ao receber informações do terminal, possivelmente o problema não é procurar.
Se esse número 14 for um erro (um código de erro definido por falhas nas chamadas do sistema), na maioria dos sistemas, isso seria EFAULT
( Endereço incorreto ). A read()
chamada do sistema falharia com esse erro se solicitada a leitura em um endereço de memória que não seja gravável. Isso seria independente de o fd ler os dados dos pontos em um canal ou arquivo regular e geralmente indicaria um erro 1 .
binary
possivelmente determina o tipo de arquivo aberto em seu stdin (with fstat()
) e se depara com um erro quando não é um arquivo comum nem um dispositivo tty.
Difícil dizer sem saber mais sobre o aplicativo. Executá-lo sob strace
(ou truss
/ tusc
equivalente em seu sistema) pode ajudar-nos a ver o que é a chamada de sistema se houver que está a falhar aqui.
1 O cenário previsto por Matthew Ife em um comentário à sua pergunta parece muito plausível aqui. Citando-o:
Suspeito que ele esteja buscando no final do arquivo obter um tamanho de buffer para ler os dados, lidando mal com o fato de que a busca não funciona e tentando alocar um tamanho negativo (não lidando com um malloc ruim). Passar o buffer para ler quais falhas, dadas o buffer, não são válidas.