He canalizado una línea en el script bash y quiero verificar si la tubería tiene datos, antes de alimentarla a un programa.
Buscando encontré test -t 0pero no funciona aquí. Siempre devuelve falso. Entonces, ¿cómo estar seguro de que la tubería tiene datos?
Ejemplo:
echo "string" | [ -t 0 ] && echo "empty" || echo "fill"
Salida: fill
echo "string" | tail -n+2 | [ -t 0 ] && echo "empty" || echo "fill"
Salida: fill
¿A diferencia de la forma estándar / canónica de probar si la tubería anterior produjo salida? la entrada necesita ser preservada para pasarla al programa. Esto generaliza ¿Cómo canalizar la salida de un proceso a otro pero solo se ejecuta si el primero tiene salida? que se centra en enviar correos electrónicos.

Respuestas:
No hay forma de ver el contenido de una tubería utilizando utilidades de shell comúnmente disponibles, ni hay una manera de leer un carácter en la tubería y luego volver a colocarlo. La única forma de saber que una tubería tiene datos es leer un byte, y luego debe llevar ese byte a su destino.
Así que haz eso: lee un byte; si detecta un final de archivo, haga lo que quiera hacer cuando la entrada esté vacía; si lee un byte, bifurque lo que quiere hacer cuando la entrada no esté vacía, canalice ese byte en él y canalice el resto de los datos.
La
ifneutilidad de moreutils de Joey Hess ejecuta un comando si su entrada no está vacía. Por lo general, no se instala de manera predeterminada, pero debería estar disponible o ser fácil de construir en la mayoría de las variantes de Unix. Si la entrada está vacía,ifneno hace nada y devuelve el estado 0, que no se puede distinguir del comando que se ejecuta correctamente. Si desea hacer algo si la entrada está vacía, debe hacer arreglos para que el comando no devuelva 0, lo que puede hacerse haciendo que el caso de éxito devuelva un estado de error distinguible:test -t 0no tiene nada que ver con esto; prueba si la entrada estándar es un terminal. No dice nada de una forma u otra sobre si hay alguna entrada disponible.fuente
peekque pueda devolver los datos reales de una tubería, no solo la cantidad que hay. (en 4.4 BSD, 386BSD, etc., las tuberías se implementaron como pares de zócalos , pero eso fue destripado en versiones posteriores de * BSD, aunque las mantuvieron bidireccionales).read -t 0(t en este caso significa tiempo de espera, si se pregunta).Una solución simple es usar el
ifnecomando (si la entrada no está vacía). En algunas distribuciones, no está instalado por defecto. Es una parte del paquetemoreutilsen la mayoría de las distribuciones.ifneejecuta un comando dado si y solo si la entrada estándar no está vacíaTenga en cuenta que si la entrada estándar no está vacía, se pasa
ifneal comando dadofuente
Antigua pregunta, pero en caso de que alguien la encuentre como yo: mi solución es leer con tiempo de espera.
Si
stdinestá vacío, esto regresará después de 5 segundos. De lo contrario, leerá toda la entrada y podrá procesarla según sea necesario.fuente
-tlamentablemente no forma parte de POSIX: pubs.opengroup.org/onlinepubs/9699919799/utilities/read.htmlcompruebe si el descriptor de archivo de stdin (0) está abierto o cerrado:
fuente
[ -t 0 ]comprueba si fd 0 está abierto en un tty , no si está cerrado o abierto../that_script </dev/null=> "stdin tiene datos". O./that_script <&-tener el stdin realmente cerrado .También puede usar
test -s /dev/stdin(en una subshell explícita).fuente
En bash:
Detecta si una entrada tiene datos (sin leer nada). Luego puede leer la entrada (si la entrada está disponible en el momento en que se ejecuta la lectura):
Nota: Comprenda que esto depende del tiempo. Esto detecta si la entrada ya tiene datos solo en el momento en que se
read -tejecuta.Por ejemplo, con
la salida es
1(falla de lectura, es decir: entrada vacía). El eco escribe algunos datos, pero no es muy rápido para iniciar y escribir su primer byte, por lo tanto,read -t 0informará que su entrada está vacía, ya que el programa aún no ha escrito nada.fuente
bashhará unaselect()o unaioctl(FIONREAD), o ninguna de ellas, pero no ambas, como debería para que funcione.read -t0está roto. No lo useUna manera fácil de verificar si hay datos disponibles para leer en Unix es con el
FIONREADioctl.No puedo pensar en ninguna utilidad estándar que haga exactamente eso, así que aquí hay un programa trivial que lo hace (mejor que el
ifnede moreutils en mi humilde opinión ;-)).Si no hay datos disponibles en stdin, saldrá con el estado 1. Si hay datos, se ejecutará
prog. Si noprogse da, saldrá con el estado 0.Puede eliminar la
pollllamada si solo le interesan los datos disponibles de inmediato . Esto debería funcionar con la mayoría de los tipos de fds, no solo con tuberías.fionread.c
fuente
POLLHUPevento también para manejar el caso vacío? ¿Funciona eso si hay varias descripciones de archivos en el otro extremo de la tubería?Si te gustan las frases cortas y crípticas:
Usé los ejemplos de la pregunta original. Si no desea la
-qopción de uso de datos canalizados con grepfuente
Esto parece ser una implementación razonable de ifne en bash si estás de acuerdo con leer toda la primera línea
fuente
readtambién devolverá falso si la entrada no está vacía pero no contiene caracteres de nueva línea,readrealiza algún procesamiento en su entrada y puede leer más de una línea a menos que la llame comoIFS= read -r line.echono se puede usar para datos arbitrarios.Esto funciona para mí usando
read -rt 0ejemplo de la pregunta original, sin datos:
fuente
{ sleep .1; echo yes; } | { read -rt0 || echo NO; cat; }(falso negativo) ytrue | { sleep .1; read -rt0 && echo YES; }(falso positivo). De hecho, Bashreadse deje engañar incluso por FDS abiertas en sólo escritura modo:{ read -rt0 && echo YES; cat; } 0>/tmp/foo. Lo único que parece hacer esselect(2)en ese fd.selectdevolverá un fd como "listo" si unread(2)en él no se bloquea, no importa si regresaráEOFo si se produjo un error. Conclusión:read -t0se rota enbash. No lo uses{ sleep .1; echo yes; } | { read -rt0 || echo NO; cat; }no es un falso negativo porque (en el momento en que se ejecuta la lectura) no hay entrada. Más tarde (suspensión .1) esa entrada está disponible (para el gato).echo "" | { read -t0 && echo YES; }imprime SÍ peroecho "" | { read -rt0 && echo YES; }no lo hace.