Normalmente, quando se trabalha com tubos e stdin, um tubo esgotado não tem significado especial. Novos dados ainda podem aparecer até que haja um eof que feche o canal. Seu cat termina em eof conforme o esperado. Se não houver dados antes de eof , só então você poderá dizer que o stdin estava realmente vazio.
Considere sender | receiver . Não é incomum que o sender seja (muito) mais lento que o receiver ; Nesse caso, o stdin de receiver é quase sempre esgotado, mas você dificilmente quer matar o cachimbo inteiro por causa disso. Portanto, as ferramentas que saem em stdin "vazio" (esgotado, mas ainda não terminado) são exceções em vez de padrão.
No Bash existe read -t 0 ( -t não é requerido pelo POSIX). De help read :
If
TIMEOUTis0,readreturns immediately, without trying to read any data, returning success only if input is available on the specified file descriptor.
Por padrão, read lê stdin, então o status de saída de read -t 0 dirá se o stdin está "vazio". Mas cuidado! Um comando como
echo 1 | read -t 0
pode sair com êxito ou não, porque echo e read são executados simultaneamente, não sequencialmente. Para evitar isso, seu script deve sleep por um tempo antes de read -t 0 . Dependendo de onde o stdin vem, "um tempo" pode ser relativamente longo. Faça algo assim:
sleep 1
if read -t 0; then … # process stdin here, you know it's non-empty
Você preenche uma variável com dados obtidos de stdin. Como armazenar dados binários em uma variável não é uma boa idéia (leia isso ), talvez seus dados sejam apenas texto. Em caso afirmativo, use read -t da seguinte forma:
read -r -t 5 -d $'timeout --foreground 5 cat | wc -c
' stdin
Caractere nulo (que você não pode armazenar em uma variável do Bash) como um delimitador ( -d $' ) permitirá que você leia qualquer texto (por exemplo, com novas linhas) para a variável stdin'-t 5 . Depois de no máximo 5 segundos ( timeout ), o comando termina, permitindo que seu script continue.
Outra abordagem é com wc -c . Um exemplo básico do meu Debian:
{ timeout --foreground 5 dd bs=1 count=1 2>/dev/null && cat; } | wc -c
(Substitua cat pelo seu código que analisa stdin; é apenas um exemplo).
Isso deve lidar com dados binários muito bem. Se eof não obtiver wc , depois de 5 segundos ele será eliminado, portanto, eof obterá cat de qualquer maneira e a linha não será paralisada. O problema é que cat será eliminado, independentemente de estar processando algum dado no momento. Eu imagino que você quer obter todos os dados, se houver algum, mesmo que demore mais de 5 segundos. Versão melhorada:
echo 1 | read -t 0
Se o primeiro byte aparecer dentro de 5 segundos, eof será acionado. Em seguida, ele processará qualquer entrada adicional até wc , independentemente do tempo necessário. Tudo incluindo o primeiro byte (se houver) irá para eof . Se não houver um byte nem wc em 5 segundos, eof receberá apenas %code% ; a linha não fica parada.