Cuenta el número de líneas de salida del programa anterior

32

Estoy tratando de contar el número de líneas de salida que produce un determinado programa. El problema es que el programa tarda mucho en ejecutarse y quiero mostrar el resultado al usuario. ¿Hay alguna manera de contar el número de líneas que emitió el último comando?

Podría hacerlo, program | wc -lpero eso no mostraría el resultado al usuario. Por lo que sé, tengo que hacerlo program; program | wc -l, pero el programa tarda al menos un minuto en ejecutarse, por lo que no quiero tener que hacerlo más de una vez solo para mostrar un recuento de líneas en la parte inferior.

EDITAR:

  • ¿Hay alguna forma de mostrar el resultado tal como sucede (línea por línea) y luego devolver un conteo al final?
Libbux
fuente
Qué tal: haga que el programa haga un seguimiento de su propia salida y simplemente lea ese valor de la variable (por ejemplo STDOUT_WRITE_COUNT), o lo registre en un archivo / API, al final del programa. WDYT?
mecampbellsoup

Respuestas:

43

Puede usar teepara dividir el flujo de salida enviando una copia wcy la otra copia a STDOUT como de costumbre.

program | tee >(wc -l)

La >(cmd)sintaxis es bash, lo que significa ejecutar cmdy reemplazar el >(cmd)bit con la ruta a (una tubería con nombre conectada a) el STDIN de ese programa.

Patricio
fuente
2
>(cmd)esta kshsintaxis también es reconocida por zshy bashy solo usa canalizaciones con nombre en sistemas que no tienen /dev/fd/n.
Stéphane Chazelas
@StephaneChazelas Sí, la mayoría de los shells lo admiten, pero no está en POSIX, por lo que no se puede confiar en que esté en todas partes.
Patrick
Sí, solo estaba señalando que la sustitución del proceso no era una bashinvención, ya que la redacción de su respuesta podía dejarle creer.
Stéphane Chazelas
1
@TheLibbster Depende de cómo se defina eficiente. Este método implica generar 2 procesos adicionales, donde as sedy awkson solo uno. Pero teey wcson extremadamente pequeños (mucho más pequeños que sedy awk).
Patrick
1
@TheLibbster sí, según algunas pruebas simples que acabo de hacer, en realidad es aproximadamente el doble de rápido que los métodos sedy awk. (Le di dd100mb /dev/urandoma un archivo y luego ejecuté ese archivo a través de cada método varias veces)
Patrick
10

Una opción es usar awk, que puede contar e imprimir en stdout.

program | awk '{ print } END { print NR }'

En awk, NR es el número de línea actual. Puedes lograr lo mismo con perl:

program | perl -pe 'END {print "$.\n"}'

O sed:

program | sed -n 'p;$='
jordanm
fuente
¿Hay alguna forma de mostrar el resultado tal como sucede (línea por línea) y luego devolver un conteo al final?
Libbux
6

Puede clonar stdout en stderr.

program | tee /dev/stderr | wc -l

De esa manera, programel stdout se canaliza para teeescribirse en stderr, que está impreso en la consola. teetambién escribe los datos canalizados a él en su stdout, que se canaliza a wc.


fuente
3

mi opción favorita:

program | grep "" -c
montells
fuente
1
Puede que OP haya preguntado algo más, pero vine aquí buscando obtener un recuento del número de líneas de salida y no me importó mostrar la salida real, y esto hace el trabajo. ¡Gracias!
Nikhil VJ
0
tail -f /var/log/squid/access.log | ( c=0; pl() { echo $c; c=0; }; trap pl SIGHUP; while read a; do (( c=c+1 )); done ) & ( trap 'kill $! ; exit' SIGINT; trap '' SIGHUP; while true; do kill -HUP $! ; sleep 1; done)
zlob
fuente
0

Esto puede llegar tarde. Pero solo abordaría su pregunta de seguimiento sobre cómo atrapar el número contado en una variable.

Esto es lo que quieres YOUR_VAR=$(PROGRAM | tee /dev/stderr | wc -l).

Aprovechamos la teegeneración de dos secuencias aquí y dirigimos una a /dev/stderr, que aparecería en su pantalla, y la otra a wc -l, que informaría el número de líneas.

huangzonghao
fuente