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", ...)