El tema de la jqnecesidad de un filtro explícito cuando la salida se redirige se discute en toda la web. Pero no puedo redirigir la salida si jqes parte de una cadena de tuberías, incluso cuando se usa un filtro explícito.
Considerar:
touch in.txt
tail -f in.txt | jq '.f1'
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Como se esperaba, la salida en el terminal original del jqcomando es:
1
3
Pero si agrego algún tipo de redirección o tubería al final del jqcomando, la salida se silencia:
rm in.txt
touch in.txt
tail -f in.txt | jq '.f1' | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
No aparece ninguna salida en el primer terminal y out.txt está vacío.
He probado cientos de variaciones pero es un problema difícil de alcanzar. La única solución que he encontrado , como descubrí a través de mosquitto_subThe Things Network (que también descubrí el problema), es envolver las funciones tail y jq en un script de shell:
#!/bin/bash
tail -f $1 | while IFS='' read line; do
echo $line | jq '.f1'
done
Luego:
./tail_and_jq.sh | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Y, efectivamente, aparece la salida:
1
3
Esto es con la última jqversión instalada a través de Homebrew:
$ echo $SHELL
/bin/bash
$ jq --version
jq-1.5
$ brew install jq
Warning: jq 1.5_3 is already installed and up-to-date
¿Es esto un error (en gran parte indocumentado) en jqmi comprensión de las cadenas de tuberías?
fuente

tail -fpara proporcionar una entrada continua a un programa yteeprocesar la salida. Si todavía necesitara una respuesta, le habría sugerido que simplificara la cadena para<in.json jq '.f1' >out.jsonpoder reducir la causa.tail -f logfile | grep 'foo bar' | awk ...tailbit surgió de los esfuerzos por romper la tubería (ejecute el primer comando, coloque en T y redirija al archivo, siga esa cola, canalice al siguiente comando, redirija al archivo, etc.) y ejecútelo continuamente en secciones. Sin<embargo, es una buena herramienta para tener en cuenta.Respuestas:
La salida de
jqse almacena cuando se canaliza su salida estándar.Para solicitar que
jqvacíe su búfer de salida después de cada objeto, use su--unbufferedopción, por ej.Del
jqmanual:fuente
Lo que estás viendo aquí es el buffering de C stdio en acción. Almacenará la salida en un búfer hasta que alcance un cierto límite (puede ser 512 bytes, o 4KB o más) y luego lo enviará todo de una vez.
Este almacenamiento en búfer se deshabilita automáticamente si stdout está conectado a un terminal, pero cuando está conectado a una tubería (como en su caso), habilitará este comportamiento de almacenamiento en búfer.
La forma habitual de deshabilitar / controlar el almacenamiento en búfer es usar la
setvbuf()función (consulte esta respuesta para obtener más detalles), pero eso debería hacerse en el código fuente dejqsí mismo, por lo que tal vez no sea algo práctico para usted ...Hay una solución alternativa ... (Un truco, se podría decir). Hay un programa llamado "unbuffer", que se distribuye con "esperar" que puede crear un pseudo-terminal y conectarlo a un programa. Por lo tanto, aunque
jqseguirá escribiendo en una tubería, pensará que está escribiendo en una terminal y se deshabilitará el efecto de almacenamiento en búfer.Instale el paquete "expect", que debería venir con "unbuffer", si aún no lo tiene ... Por ejemplo, en Debian (o Ubuntu):
Entonces puedes usar este comando:
Consulte también esta respuesta para obtener más detalles sobre "unbuffer", y también puede encontrar una página de manual aquí .
fuente
jqimplementa de forma nativa la salida sin búfer, por lo que no hay necesidad de la solución.jqpágina de manual, pero me aburrí después de un tiempo y fui a hacer otras cosas ... ¡Es bueno saber que hay algo así! :-)stdbuf -o0que inyectarán código a través de LD_PRELOAD y harán lasetvbuf()llamada mágica por usted. Si funciona en macOS, no estoy seguro.expectestá preinstalado en macos,unbufferno lo está. Sin embargo, es parte del paquete Homebrew, por lo que en macosbrew install expectlo hará.