
He entrado en un estado interesante en Ubuntu. Los pasos a continuación lo describen mejor.
Con un solo tubo, estoy viendo lo que espero.
# In shell A
tail -f foo.log | grep aaa
# In shell B
echo aaa >> foo.log
# Shell A prints out `aaa`
Pero con múltiples tuberías no veo nada en absoluto.
# In shell A
tail -f foo.log | grep aaa | grep bbb
# In shell B
echo aaa bbb >> foo.log
# Nothing ever prints in shell A
Pero funciona bien si solo hago eco.
echo 'aaa bbb' | grep aaa | grep bbb
Este es mi intento de crear una reproducción mínima. Originalmente encontré el problema al intentar obtener registros desde adb logcat (herramientas de desarrollo de Android). También lo probé en zsh, bash y fish.
Supuse que tenía algo que ver con mi límite de observador de inotify, pero aumentarlo no cambió nada.
Respuesta1
Esto se debe al almacenamiento en búfer en la tubería, que en general no se preocupa por las líneas y puede acumular datos.
Creo que tail -f
utiliza el almacenamiento en búfer de línea por sí solo; y el último grep
escribe en el tty, por lo que también usa almacenamiento en búfer de línea. Por lo tanto, su primer ejemplo funciona.
Pero grep
en el medio es diferente y es necesario ajustar su comportamiento forzando el almacenamiento en búfer de línea o deshabilitando el almacenamiento en búfer. Los siguientes comandos funcionarán como esperaba.
Si su
grep
soporte--line-buffered
(lo hace en Ubuntu):tail -f foo.log | grep --line-buffered aaa | grep bbb
Soluciones más genéricas (funcionarán con muchos filtros distintos de
grep
):tail -f foo.log | unbuffer -p grep aaa | grep bbb tail -f foo.log | stdbuf -oL grep aaa | grep bbb tail -f foo.log | stdbuf -o0 grep aaa | grep bbb
Consulte man 1 grep
y para man 1 unbuffer
obtener man 1 stdbuf
detalles y peculiaridades.
Notas:
- Ninguna de las soluciones es portátil (
grep --line-buffered
y no están especificadas por POSIX).unbuffer
stdbuf
- Si puedes hacer esto,
grep --line-buffered
entonces debería ser tu elección. No tiene sentido utilizar herramientas adicionales. - Pregunta relacionada sobre Unix y Linux SE:Desactivar el almacenamiento en búfer en la tubería.
unbuffer
ystdbuf
trabajar de maneras completamente diferentes.- Con , aquí se debe preferir
stdbuf
el almacenamiento en búfer de línea ( ) a no tener almacenamiento en búfer ( ), porque-oL
-o0
- lo más probable es que funcione mejor,
- y otras partes de su tubería usan buffering de línea de todos modos.
- Si
grep
escribió por última vez en otro archivo, se comportaría como el otrogrep
. En tal caso, si desea que aparezcan líneas en el archivo final inmediatamente, también debe modificar el comportamiento del último archivogrep
. - En
fish
, sigrep
es una función contenedora, es posible que no obtenga el comportamiento deseado con--line-buffered
. Usarcommand grep --line-buffered
. Vea esta pregunta:La tubería de salida espera la entrada de EOFfish
.
Nota al margen: tail foo.log | grep aaa | grep bbb
(es decir, tail
sin -f
) no causa el problema porque tail
sale. Cuando tail
sale, el primero grep
detecta EOF, vacía su búfer y sale, luego el segundo grep
hace lo mismo.