Comment faire un 'wc -l' continu avec gnu texttools?

28

Je sais bien sûr que

cat logfile.txt | wc -l
120

me dira le nombre de lignes dans un fichier.

Tandis que

tail -f logfile.txt

me montrera les nouvelles lignes dans lesquelles un autre programme écrit logfile.txt.

Est-il possible de combiner les deux pour obtenir un nombre de lignes de mise à jour continue de logfile.txt avec des utilitaires de texte standard?

Je connais

watch wc -l logfile.txt

mais je ne veux pas recompter tout le dossier à chaque fois, cela semble être un gaspillage. On aurait besoin d'un comptage en annexe uniquement toutes les secondes environ et probablement un \rau lieu d'un \nà la fin de la ligne.

towi
la source
1
Votre fichier est-il si gros que tout raconter est un problème? En termes de déchets: la tuyauterie en catsortie wcest aussi un gros gaspillage !!
Bernhard
Oui, c'est potentiellement très gros.
towi

Réponses:

36

Peut être:

tail -n +1 -f file | awk '{printf "\r%lu", NR}'

Méfiez-vous qu'il afficherait un nombre pour chaque ligne d'entrée (mais en remplaçant la valeur précédente s'il était envoyé à un terminal).

Ou vous pouvez implémenter le tail -fà la main dans le shell:

n=0
while :; do 
  n=$(($n + $(wc -l)))
  printf '\r%s' "$n"
  sleep 1
done < file

(notez qu'il s'exécute jusqu'à une wcet une sleepcommande par seconde que tous les shells n'ont pas intégrés. Avec ksh93while sleepest intégré, pour obtenir un intégré wc(au moins sur Debian), vous devez ajouter /opt/ast/binà l'avant de $PATH(indépendamment du fait que ce répertoire existe ou non) ou utilisezcommand /opt/ast/bin/wc (ne demandez pas ...)).

Vous pouvez utiliser pv, comme dans:

tail -n +1 -f file | pv -bl > /dev/null

Mais attention, il ajoute k, M... suffixes lorsque le nombre est supérieur à 1000 (et il ne semble pas y avoir de solution ).

Stéphane Chazelas
la source
Whow à votre tail | awksolution. Connaissez vos options: -n +0ne me serait pas venu à l'esprit dans cette combinaison.
towi
2
whoo! pv- un autre nouvel outil utile. merci beaucoup.
towi
Avec grep, vous pouvez ajouter un filtre à votre flux:tail -n +0 -f <my.log> | grep --line-buffered <mystring> | awk '{printf "\r%lu", NR}'
tombolinux
2
@tombolinux, awkest un sur-ensemble de grep. tail -n +0 -f file | awk '/mystring/ {printf "\r%lu", ++n}'
Stéphane Chazelas
Cool. J'ajoute END{print ""}pour faire awkimprimer une nouvelle ligne à la fin.
pLumo
6

Essayez de le compter avec pur bashsans wc:

a=0 ; tail -f file | while read -r line ; do ((a++)) ; echo $a ; done

ou même comme ceci pour réécrire la valeur précédente:

a=0 ; tail -f file | while read -r line ; do ((a++)) ; echo -ne "\r$a" ; done
se ruer
la source
1

Je ne crois pas qu'il y ait quelque chose comme ça. Mais il devrait être facile de préparer quelque chose comme:

#!/usr/bin/perl

$for_a_while = 1;

$oldcount = -1;
$count = 0;
open($fh, "<", $ARGV[0]);

for (;;) {
  for ($curpos = tell($fh); <$fh>; $curpos = tell($fh)) {
    $count++;
  }
  if($count != $oldcount) {
    print "$count\n";
    $oldcount = $count;
  }
  sleep($for_a_while);
  seek($fh, $curpos, 0);
}

(Idée générale tirée de perlfunc(1))

vonbrand
la source
1
Le nombre augmente chaque fois que vous effectuez un printf foo >> file. Vous devez compter les caractères de nouvelle ligne (comme wc -ldans la solution shell que j'ai suggérée), pas les enregistrements renvoyés par <$fh>. Je ne pense pas que vous ayez besoin d'utiliser tellou pas seekdu tout.
Stéphane Chazelas
Le <$fh>lit une ligne par défaut, pas des enregistrements. La page de manuel Perl citée indique de le faire de cette façon dans un environnement éventuellement non coopératif (pourrait dépendre du système de fichiers, je suppose que NFS ou d'autres systèmes de fichiers montés sur réseau pourraient nécessiter un peu de réflexion).
vonbrand
Essayez-le par vous-même, lorsque vous atteindrez la fin du fichier, vous <$fh>retournerez un enregistrement même s'il n'est pas terminé par un caractère de nouvelle ligne. Donc, si se perltrouve à la fin du fichier, et que quelqu'un le fait plus tard printf foo >> file, alors <$fh>reviendra foo(pas une ligne car il n'est pas terminé par un caractère de nouvelle ligne), et $countsera incrémenté même si aucune ligne supplémentaire n'a été ajoutée au fichier.
Stéphane Chazelas
OP était censé surveiller les fichiers journaux écrits une ligne à la fois?
vonbrand
Non, c'est pourquoi votre solution peut ne pas fonctionner. Par exemple, si les applications écrivant dans le fichier mettent en mémoire tampon sa sortie, à tout moment, la dernière ligne ne sera probablement pas terminée et sera donc comptée deux fois.
Stéphane Chazelas
0

Poursuivre la solution basée sur awk: vous n'aurez peut-être pas besoin de voir le compteur cocher pour chaque ligne de votre journal; si c'est le cas, vous pouvez l'avoir comme ceci (le nombre changerait pour chaque 10 lignes):

tail -n +0 logfile.txt | \
    awk 'a+=1{}a%10==0{printf "\r%lu", a}END{printf "\r%lu", a}'
artyom
la source