Compter le nombre de lignes de sortie du programme précédent

32

J'essaie de compter le nombre de lignes de sortie produites par un programme donné. Le problème est que l'exécution du programme prend beaucoup de temps et je souhaite afficher la sortie à l'utilisateur. Existe-t-il un moyen de compter le nombre de lignes de la dernière commande sortie?

Je pourrais le faire program | wc -lmais cela ne montrerait pas la sortie à l'utilisateur. Donc, autant que je sache, je dois le faire program; program | wc -l- mais le programme prend au moins une minute, et je ne veux donc pas le faire plus d'une fois, juste pour afficher un nombre de lignes en bas.

MODIFIER:

  • Existe-t-il un moyen d'afficher la sortie au fur et à mesure (ligne par ligne), puis de renvoyer un compte à la fin?
Libbux
la source
Que diriez-vous: demandez au programme de garder une trace de sa propre sortie et de simplement lire cette valeur dans la variable (par exemple STDOUT_WRITE_COUNT) ou de la consigner dans un fichier / API à la fin du programme. WDYT?
mecampbellsoup

Réponses:

43

Vous pouvez utiliser teepour diviser le flux de sortie en envoyant une copie à wcl'autre et STDOUT comme d'habitude.

program | tee >(wc -l)

La >(cmd)syntaxe is bash, qui signifie exécuter cmdet remplacer le >(cmd)bit par le chemin d'accès (un canal nommé connecté à), le STDIN de ce programme.

Patrick
la source
2
>(cmd)Cette kshsyntaxe est également reconnue par zshet bashet n'utilise que des canaux nommés sur des systèmes qui n'en ont pas /dev/fd/n.
Stéphane Chazelas
@StephaneChazelas Oui, la plupart des obus le supportent, mais ce n'est pas dans POSIX, on ne peut donc pas compter sur lui pour être partout.
Patrick
Oui, je soulignais simplement que la substitution de processus n'était pas une bashinvention, car le libellé de votre réponse pouvait laisser croire.
Stéphane Chazelas
1
@TheLibbster Cela dépend de votre définition de l'efficacité. Cette méthode implique la création de 2 processus supplémentaires, où as sedet ne awksont qu'un. Mais teeet wcsont tous deux extrêmement petits (beaucoup plus petits que sedet awk).
Patrick
1
@ TheLibbster oui, selon certains tests simples que je viens de faire, il est en fait environ deux fois plus rapide que les méthodes sedand awk. (Je ddd 100mb de /dev/urandomdans un fichier et ensuite couru ce fichier à travers chaque méthode plusieurs fois)
Patrick
10

Une option consiste à utiliser awk, qui peut effectuer le comptage et l’impression sur la sortie standard.

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

In awk, NR est le numéro de ligne actuel. Vous pouvez accomplir la même chose avec perl:

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

Ou sed:

program | sed -n 'p;$='
Jordan
la source
Existe-t-il un moyen d'afficher la sortie au fur et à mesure (ligne par ligne), puis de renvoyer un compte à la fin?
Libbux
6

Vous pouvez cloner stdout sur stderr.

program | tee /dev/stderr | wc -l

De cette façon, programla sortie standard de stdout teedoit être écrite sur stderr, qui est imprimée sur la console. teeécrit également les données qui lui sont transmises sur sa stdout, qui est dirigée vers wc.


la source
3

mon option préférée:

program | grep "" -c
Montells
la source
1
OP a peut-être demandé autre chose, mais je suis venu ici pour obtenir un nombre de lignes uniquement, sans me soucier de l'affichage de la sortie réelle, ce qui fait le travail. Merci!
Nikhil VJ le
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
la source
0

C'est peut-être tard. Mais je voudrais juste répondre à votre question suivante sur la façon d’attraper le nombre compté dans une variable.

C'est ce que tu veux YOUR_VAR=$(PROGRAM | tee /dev/stderr | wc -l).

Nous profitons de la teegénération de deux flux ici et dirigeons l'un vers /dev/stderr, ce qui apparaîtrait sur votre écran, et l'autre wc -l, qui indiquerait le nombre de lignes.

huangzonghao
la source