¿Puedo desactivar el almacenamiento en búfer para tr

10

trparece amortiguar su entrada para que este comando LongRunningCommand|tr \\n ,solo comience a producir resultados después de que se hayan acumulado unos pocos kilobytes de entrada de LongRunningCommand.

¿Hay alguna forma de forzar tra detener este almacenamiento en búfer o cualquier otro comando que pueda reemplazar las nuevas líneas con otro carácter sin almacenar en búfer?


PD: Ya he probado las dos primeras sugerencias de Desactivar el almacenamiento en búfer en la tubería sin éxito.

ndemou
fuente
1
¿ stdbufaplicaste a LongRunningCommand o tr, o a ambos, de manera diferente?
meuh
A ambos les gusta esto:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
ndemou
fping -qdice "No mostrar los resultados por sondeo, sino solo el resumen final", ¿entonces tal vez solo escriba uno largo al final?
meuh
No, el comando fping funciona bien por sí mismo. Muchas gracias por las sugerencias sin embargo
ndemou
2
Creo que el problema del búfer está realmente en la salida de tr. Prueba|stdbuf -i0 -o0 tr ...
meuh

Respuestas:

12

Los comandos generalmente no almacenan en búfer su entrada. Ellos hacen un read()para una gran parte, pero cuando se lee de un tubo, si no hay que muchos bytes de la tubería, la read()llamada al sistema volverán con el mayor número de caracteres que hay y la aplicación generalmente trabajar con eso, si puede .

Una notable excepción a eso es mawkque seguirá apareciendo read()hasta que el búfer de entrada esté lleno.

Sin embargo, las aplicaciones amortiguan su salida (stdout). El comportamiento habitual es que si la salida va a un tty, entonces el almacenamiento en búfer será en línea (es decir, no comenzará a escribir en stdout hasta que tenga una línea completa para la salida, o un bloque lleno por mucho tiempo). línea larga), mientras que para cualquier otro tipo de archivo, el almacenamiento en búfer es por bloques (es decir, no comenzará a escribir hasta que tenga un bloque lleno para escribir (algo como 4KiB / 8KiB ... depende del software y el sistema )).

Entonces, en su caso, es LongRunningCommandprobable que amortigüe su salida por bloques (ya que su salida es una tubería y no un tty), y trprobablemente amortigua su salida por línea, ya que su salida es probablemente la terminal.

Pero, dado que elimina todos los caracteres de nueva línea de su salida, nunca generará una línea, por lo que el almacenamiento en búfer será por bloque.

Entonces, aquí desea deshabilitar el almacenamiento en búfer para ambos LongRunningCommandy tr. En sistemas GNU o FreeBSD:

stdbuf -o0 LongRunningCommand | stdbuf -o0 tr '\n' ,

Tenga en cuenta que si desea unir las líneas con una coma, es mejor utilizar un enfoque paste -sd , -. De esa manera, la salida se terminará con un carácter de nueva línea (probablemente aún tendrá que deshabilitar el almacenamiento en búfer).

Stéphane Chazelas
fuente
@mikeserv. Sí, y uno que usa el almacenamiento en búfer stdio y no llama a setvbuf / setbuffer ... por sí mismo y no es un shell incorporado. Pero generalmente en los sistemas GNU y FreeBSD, todas esas condiciones se cumplen.
Stéphane Chazelas
Oh. Hace unos días, solo me enteré de eso cuando estaba decepcionado de no poder afectar las transmisiones de E / S para mi compilación estática sed. lo siento si fue molesto, pero no me di cuenta de que era conocimiento general. Supongo que usa LD_PRELOAD.
mikeserv
Gracias por la explicación detallada de lo que sucede Stéphane. Muy apreciado
ndemou
5

Para reemplazar las nuevas líneas con ",", puede ejecutar

awk '{ printf "%s,", $0 }'

GNU awk ( gawk) y Solaris nawkse ejecutarán con buffering de línea en stdin y sin stdout de buffering cuando la salida es a una terminal. Si su awk es mawk, lo que sucede en Ubuntu, puede darle la -W interactiveopción de obtener el mismo comportamiento de almacenamiento en búfer.

Mark Plotnick
fuente