Come fare un continuo "wc -l" con gli strumenti di testo gnu?


28

Lo so naturalmente

cat logfile.txt | wc -l
120

mi dirà il numero di righe in un file.

Mentre

tail -f logfile.txt

mi mostrerà le nuove righe in cui scrive un altro programma logfile.txt.

È possibile combinare entrambi in modo da ottenere un conteggio di riga di aggiornamento continuo di logfile.txt con utilità di testo standard?

Lo so

watch wc -l logfile.txt

ma non voglio contare nuovamente l'intero file ogni volta, sembra uno spreco. Uno avrebbe bisogno di un conteggio solo aggiunto ogni secondo circa e probabilmente un \rinvece di un \nalla fine della riga.


1
Il tuo file è così grande che raccontare tutto è un problema? In termini di rifiuti: anche la catproduzione di tubazioni wcè un grande spreco !!
— Bernhard,

Sì, potenzialmente è molto grande.
— towi,

Risposte:


36

Può essere:

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

Attenzione che produrrebbe un numero per ogni riga di input (anche se sovrascrive il valore precedente se inviato a un terminale).

Oppure puoi implementare tail -fa mano nella shell:

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

(nota che esegue fino a uno wce un sleepcomando al secondo che non tutte le shell hanno incorporato. Con ksh93while sleepè incorporato, per ottenere un built-in wc(almeno su Debian), devi aggiungere /opt/ast/binin primo piano $PATH(indipendentemente dal fatto che quella directory esiste o no) o usa command /opt/ast/bin/wc(non chiedere ...)).

Puoi usare pv, come in:

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

Ma attenzione che aggiunge k, M... suffissi quando il numero è superiore a 1000 (e non sembra esserci un modo per aggirare questo ).


Whow alla tua tail | awksoluzione. Conosci le tue opzioni: -n +0non mi sarebbe venuto in mente in questa combinazione.
— towi,

2
Whoo! pv- un altro utile nuovo strumento. grazie mille.
— towi,

Con grep puoi aggiungere un filtro al tuo stream:tail -n +0 -f <my.log> | grep --line-buffered <mystring> | awk '{printf "\r%lu", NR}'
— tombolinux l'

2
@tombolinux, awkè un superset di grep. tail -n +0 -f file | awk '/mystring/ {printf "\r%lu", ++n}'
— Stéphane Chazelas,

Freddo. Aggiungo END{print ""}per rendere la awkstampa una nuova riga alla fine.
— pLumo,

6

Prova a contarlo con puro bashsenza wc:

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

o anche così per riscrivere il valore precedente:

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

1

Non credo ci sia niente del genere. Ma dovrebbe essere facile montare qualcosa sulla falsariga di:

#!/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);
}

(Idea generale paralizzata da perlfunc(1))


1
Il numero aumenterebbe ogni volta che si esegue un printf foo >> file. Dovresti contare i caratteri di nuova riga (come wc -lnella soluzione shell che ho suggerito), non i record restituiti da <$fh>. Non penso che tu debba usare tello seekaffatto.
— Stéphane Chazelas,

Per <$fh>impostazione predefinita legge una riga, non i record. La manpage Perl citata dice di farlo in questo modo per un ambiente forse non collaborativo (potrebbe dipendere dal filesystem, immagino che NFS o altri filesystem montati in rete potrebbero richiedere un po 'di stimolo).
— vonbrand,

Provalo tu stesso, una volta raggiunta la fine del file, <$fh>restituirà un record anche se non è terminato da un carattere di nuova riga. Quindi, se si perltrova alla fine del file e qualcuno in seguito lo fa printf foo >> file, allora <$fh>tornerà foo(non una linea poiché non è terminato da un carattere di nuova riga) e $countverrà incrementato anche se non è stata aggiunta alcuna riga aggiuntiva al file.
— Stéphane Chazelas,

L'OP doveva monitorare i file di log scritti una riga alla volta?
— vonbrand,

No, ecco perché la tua soluzione potrebbe non funzionare. Ad esempio, se le applicazioni che scrivono nel file ne bufferizzano l'output, allora in qualsiasi momento, è probabile che l'ultima riga non venga terminata, quindi verrà conteggiata due volte.
— Stéphane Chazelas,

0

Continuando la soluzione basata su awk: potrebbe non essere necessario vedere il segno di spunta del contatore per ogni riga nel registro; in tal caso, puoi averlo così (il numero cambierebbe per ogni 10 righe):

tail -n +0 logfile.txt | \
    awk 'a+=1{}a%10==0{printf "\r%lu", a}END{printf "\r%lu", a}'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.