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
TIMEOUT
is0
,read
returns 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.