Normalmente, tr
não deve poder gravar essa mensagem de erro porque ela deveria ter sido eliminada por um sinal SIGPIPE ao tentar gravar algo após a outra extremidade do canal ter sido fechada após o término de head
.
Você recebe essa mensagem de erro porque, de alguma forma, o processo que está executando tr
foi configurado para ignorar SIGPIPEs. Eu suspeito que isso possa ser feito pela implementação popen()
em sua linguagem lá.
Você pode reproduzi-lo fazendo:
sh -c 'trap "" PIPE; tr -dc "[:alpha:]" < /dev/urandom | head -c 8'
Você pode confirmar o que está acontecendo:
strace -fe signal sh your-program
(ou o equivalente no seu sistema, se não estiver usando o Linux). Você verá algo como:
rt_sigaction(SIGPIPE, {SIG_IGN, ~[RTMIN RT_1], SA_RESTORER, 0x37cfc324f0}, NULL, 8) = 0
ou
signal(SIGPIPE, SIG_IGN)
feito em um processo antes que o mesmo processo ou um de seus descendentes execute o /bin/sh
que interpreta essa linha de comando e inicia tr
e head
.
Se você fizer um strace -fe write
, verá algo como:
write(1, "AJiYTlFFjjVIzkhCAhccuZddwcydwIIw"..., 4096) = -1 EPIPE (Broken pipe)
A chamada do sistema write
falha com um erro EPIPE em vez de acionar um SIGPIPE.
Em qualquer caso, tr
sairá. Ao ignorar SIGPIPE, por causa desse erro (mas que também dispara uma mensagem de erro). Quando não, sai ao receber o SIGPIPE. Você quer que ele saia, pois você não quer que ele continue lendo /dev/urandom
depois que esses 8 bytes tiverem sido read
por head
.
Para evitar essa mensagem de erro, você pode restaurar o manipulador padrão do SIGPIPE com:
trap - PIPE
Antes de chamar tr
:
popen("trap - PIPE; { tr ... | head -c 8; } 2>&1", ...)