Supongamos que tiene una tubería como la siguiente:
$ a | b
Si bdeja de procesar la entrada estándar, después de un tiempo la tubería se llena y escribe desde asu entrada estándar, se bloqueará (hasta que bcomience a procesar nuevamente o muera).
Si quisiera evitar esto, podría sentir la tentación de usar una tubería más grande (o, más simplemente buffer(1)) de esta manera:
$ a | buffer | b
Esto simplemente me daría más tiempo, pero al final afinalmente se detendría.
Lo que me encantaría tener (para un escenario muy específico que estoy abordando) es tener una tubería "con fugas" que, cuando está llena, dejaría caer algunos datos (idealmente, línea por línea) desde el búfer para permitir acontinuar procesamiento (como probablemente pueda imaginar, los datos que fluyen en la tubería son prescindibles, es decir, tener los datos procesados bes menos importante que apoder ejecutarlos sin bloquearlos).
Para resumir, me encantaría tener algo así como un búfer limitado y con fugas:
$ a | leakybuffer | b
Probablemente podría implementarlo con bastante facilidad en cualquier idioma, me preguntaba si hay algo "listo para usar" (o algo así como un bash one-liner) que me estoy perdiendo.
Nota: en los ejemplos estoy usando tuberías regulares, pero la pregunta se aplica igualmente a las tuberías con nombre
Si bien obtuve la respuesta a continuación, también decidí implementar el comando leakybuffer porque la solución simple a continuación tenía algunas limitaciones: https://github.com/CAFxX/leakybuffer

Respuestas:
La forma más fácil sería canalizar a través de algún programa que establezca la salida sin bloqueo. Aquí hay un simple perl oneliner (que puede guardar como leakybuffer ) que lo hace:
entonces tu se
a | bconvierte en:lo que hace es leer la entrada y escribir en la salida (igual que
cat(1)) pero la salida no se bloquea, lo que significa que si la escritura falla, devolverá un error y perderá datos, pero el proceso continuará con la siguiente línea de entrada, ya que ignoramos convenientemente error. El proceso tiene el tipo de línea de búfer que desea, pero vea la advertencia a continuación.puedes probar con, por ejemplo:
obtendrá un
outputarchivo con líneas perdidas (el resultado exacto depende de la velocidad de su shell, etc.) de esta manera:puedes ver dónde perdió el shell líneas después
12773, pero también una anomalía: el perl no tenía suficiente búfer,12774\npero sí1277lo hizo, así que escribió exactamente eso, por lo que el siguiente número75610no comienza al comienzo de la línea, por lo que es poco feo.Eso podría mejorarse haciendo que Perl detecte cuándo la escritura no tuvo éxito por completo, y luego intente eliminar el resto de la línea mientras ignora las nuevas líneas entrantes, pero eso complicaría mucho más el guión de Perl, por lo que se deja como un ejercicio para el lector interesado :)
Actualización (para archivos binarios): si no está procesando líneas terminadas en nueva línea (como archivos de registro o similares), debe cambiar ligeramente el comando, o Perl consumirá grandes cantidades de memoria (dependiendo de la frecuencia con la que aparecen caracteres de nueva línea en su entrada):
funcionará correctamente también para archivos binarios (sin consumir memoria adicional).
Actualización2: salida de archivo de texto más agradable: evitar búferes de salida (en
syswritelugar deprint):parece solucionar problemas con "líneas combinadas" para mí:
(Nota: se puede verificar en qué líneas se cortó la salida con:
perl -ne '$c++; next if $c==$_; print "$c $_"; $c=$_' outputoneliner)fuente
perl -w -MFcntl -e 'fcntl STDOUT,F_SETFL,O_WRONLY|O_NONBLOCK; while (<STDIN>) { print }' | aplay -t raw -f dat --buffer-size=16000, Perl parece asignar continuamente más memoria hasta que el administrador de OOM lo mata.dd'sdd oflag=nonblock status=none.$| = 1susyswrite()enfoque evita escrituras cortas siempre que las líneas sean razonablemente cortas.