Cuenta el número de bytes canalizados de un proceso a otro

17

Estoy ejecutando un script de shell que canaliza datos de un proceso a otro

process_a | process_b

¿Alguien sabe una manera de averiguar cuántos bytes se pasaron entre los dos programas? La única solución que puedo pensar en este momento sería escribir un pequeño programa c que lea de stdin, escriba en stdout y cuente todos los datos transferidos, almacenando el conteo en una variable de entorno, como:

process_a | count_bytes | process_b

¿Alguien tiene una solución más ordenada?

Simon Hodgson
fuente

Respuestas:

16

Tubería a través de dd. La entrada predeterminada de dd es stdin y la salida predeterminada es stdout; cuando termine la E / S stdin / stdout, informará a stderr sobre la cantidad de datos que transfirió.

Si desea capturar la salida de dd y los otros programas ya hablan con stderr, use otro descriptor de archivo. P.ej,

$ exec 4>~/fred
$ input-command | dd 2>&4 | output-command
$ exec 4>&-
Phil P
fuente
2
¿No podría omitir el execy simplemente enviarlo directamente al archivo? input-command | dd 2>~/fred | output-command
Pausado hasta nuevo aviso.
2
Uh si. Aparentemente estaba teniendo uno de "esos" momentos, lo siento.
Phil P
28

Utilice pv el visor de tuberías. Es una gran herramienta. Una vez que lo sepas, nunca sabrás cómo viviste sin él.

También puede mostrarle una barra de progreso y la 'velocidad' de la transferencia.

Rory
fuente
En mi búsqueda me encontré con esto, pero lo necesito para establecer una variable con el número de bytes transferidos para poder usarlo en otro proceso.
Simon Hodgson
Ejemplo de uso: cat file | pv -bdevolverá el tamaño del archivo.
rodorgas
6

process_a | tee >(process_b) | wc --bytesPodría funcionar. Luego puede redirigir wcel recuento a donde lo necesite. Si process_bgenera algo a stdout/ stderrprobablemente necesitará redirigir esto a alguna parte, aunque solo sea /dev/null.

Para un ejemplo ligeramente artificial:

filestore:~# cat document.odt | tee >(dd of=/dev/null 2>/dev/null) | wc --bytes
4295

A modo de explicación: le teepermite dirigir la salida a múltiples archivos (más stdout) y la >()construcción es la "sustitución de procesos" de bash, lo que hace que un proceso se vea como un archivo de solo escritura en este caso para que pueda redirigir a procesos y archivos ( vea aquí , o esta pregunta + respuesta para ver un ejemplo del uso teepara enviar resultados a muchos procesos).

David Spillett
fuente
Me gusta esta solución, lamentablemente el shelll que estoy usando (BusyBox) no parece admitir la notación> (), pero proporciona una forma de hacer lo que busco.
Simon Hodgson
Sí, necesitas un bash bastante completo para tener esa característica: es el tipo de cosa que no se usa comúnmente, por lo que se elimina de los shells reducidos (incluso aquellos con el objetivo de ser más o menos compatibles con bash) como busybox para ahorrar espacio.
David Spillett
1

Sé que llego tarde a la fiesta, pero creo que tengo una buena respuesta que puede mejorar este útil hilo.
Esta es una mezcla de @Phil P y @David Spillett, pero:

  • a diferencia de @Phil P 's, evita crear un nuevo archivo
  • a diferencia de @David Spillett, mantiene la estructura de la tubería

El conteo de bytes se imprime en stdout, junto con cualquier salida de process_b.
Puede usar un prefijo para identificar la línea que contiene bytes al trabajar con la salida ( Bytes:en el ejemplo).

exec 3>&1
process_a | tee >({ echo -n 'Bytes:'; wc -c; } >&3) | process_b
exec 3>&-

ADVERTENCIA:
No confíe en el orden de las líneas en la salida. ¡
El orden es impredecible y siempre puede diferir, incluso cuando se llama al mismo script con los mismos parámetros!

Claudio
fuente
Lamentablemente, sigue siendo una construcción de solo bash ...
Mikhail T.