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.