Contar o número de linhas de saída do programa anterior

32

Estou tentando contar o número de linhas de saída que um determinado programa produz. O problema é que o programa demora muito para ser executado e eu quero exibir a saída para o usuário. Existe uma maneira de contar o número de linhas que o último comando emitiu?

Eu poderia fazer, program | wc -lmas isso não mostraria a saída para o usuário. Tanto quanto eu sei, tenho que fazer program; program | wc -l- mas o programa leva pelo menos um minuto para ser executado, então não quero fazer isso mais de uma vez apenas para mostrar uma contagem de linhas na parte inferior.

EDITAR:

  • Existe uma maneira de mostrar a saída como ela acontece (linha por linha) e depois retornar uma contagem no final?
Libbux
fonte
Que tal: faça com que o programa controle sua própria saída e apenas leia esse valor da variável (por exemplo STDOUT_WRITE_COUNT), ou faça logon em um arquivo / API, no final do programa. WDYT?
mecampbellsoup

Respostas:

43

Você pode usar teepara dividir o fluxo de saída enviando uma cópia para wce a outra cópia para STDOUT normalmente.

program | tee >(wc -l)

A >(cmd)sintaxe é bash, o que significa executar cmde substituir o >(cmd)bit pelo caminho para (um pipe nomeado conectado) ao STDIN desse programa.

Patrick
fonte
2
>(cmd)é kshtambém a sintaxe reconhecida por zshe bashe só está usando pipes nomeados em sistemas que não possuem /dev/fd/n.
Stéphane Chazelas
@StephaneChazelas Sim, a maioria dos shells suporta, mas não está no POSIX, portanto, não se pode confiar em estar em qualquer lugar.
Patrick
Sim, eu estava apenas apontando que a substituição do processo não era uma bashinvenção, pois o texto da sua resposta poderia permitir que alguém acreditasse.
Stéphane Chazelas
1
@TheLibbster Depende de como você define eficiente. Este método envolve a geração de 2 processos adicionais, onde sede como awksão apenas um. Mas teee wcsão ambos extremamente pequenos (muito menores que sede awk).
Patrick
1
@TheLibbster sim, de acordo com alguns testes simples eu fiz, é realmente cerca de duas vezes mais rápido que ambos os sede awkmétodos. (I ddd 100MB de /dev/urandompara um arquivo e, em seguida, correu esse arquivo através de cada método várias vezes)
Patrick
10

Uma opção é usar o awk, que pode fazer a contagem e imprimir no stdout.

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

In awk, NR é o número da linha atual. Você pode fazer o mesmo com o perl:

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

Ou sed:

program | sed -n 'p;$='
jordanm
fonte
Existe uma maneira de mostrar a saída como ela acontece (linha por linha) e depois retornar uma contagem no final?
Libbux
6

Você pode clonar stdout no stderr.

program | tee /dev/stderr | wc -l

Dessa forma, programo stdout do canal é canalizado para teeser gravado no stderr, que é impresso no console. teetambém grava os dados canalizados para ele em seu stdout, que é canalizado wc.


fonte
3

minha opção favorita:

program | grep "" -c
Montells
fonte
1
O OP pode ter perguntado outra coisa, mas eu vim aqui procurando apenas obter uma contagem do número de linhas de saída e não me importei em mostrar a saída real, e isso faz o trabalho. Obrigado!
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
fonte
0

Isso pode ser tarde. Mas gostaria de responder à sua pergunta de acompanhamento sobre como capturar o número contado em uma variável.

Isto é o que você quer YOUR_VAR=$(PROGRAM | tee /dev/stderr | wc -l).

Aproveitamos a teegeração de dois fluxos aqui e direcionamos um para /dev/stderr, o qual apareceria na tela, e o outro para wc -l, que reportaria o número de linhas.

huangzonghao
fonte