Jak zrobić ciągłe wc -l z narzędziami tekstowymi GNU?


28

Wiem to oczywiście

cat logfile.txt | wc -l
120

powie mi liczbę wierszy w pliku.

Natomiast

tail -f logfile.txt

pokaże mi nowe wiersze, do których pisze inny program logfile.txt.

Czy można połączyć oba, aby uzyskać ciągłą aktualizację liczby wierszy pliku logfile.txt ze standardowymi narzędziami tekstowymi?

Wiem o tym

watch wc -l logfile.txt

ale nie chcę za każdym razem przeliczać całego pliku, co wydaje się marnotrawstwem. Potrzebny byłby tylko licznik dołączany co sekundę i prawdopodobnie \rzamiast \nna końcu linii.


1
Czy Twój plik jest tak duży, że przeliczanie wszystkiego jest problemem? Jeśli chodzi o marnotrawstwo: catprodukcja rur do wcjest również dużym marnotrawstwem !!
— Bernhard

Tak, potencjalnie jest bardzo duży.
— towi

Odpowiedzi:


36

Może:

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

Uważaj, aby wyświetlał liczbę dla każdego wiersza danych wejściowych (chociaż przesłania poprzednią wartość, jeśli zostanie wysłana do terminala).

Lub możesz wdrożyć tail -fręcznie w powłoce:

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

(zwróć uwagę, że uruchamia się jedno wci jedno sleeppolecenie na sekundę, które nie zostały wbudowane we wszystkie powłoki. Gdy jest wbudowane ksh93while sleep, aby uzyskać wbudowane wc(przynajmniej w Debianie), musisz dodać /opt/ast/binz przodu $PATH(niezależnie od tego, czy ten katalog istnieje lub nie) lub użyj command /opt/ast/bin/wc(nie pytaj ...)).

Możesz użyć pv, jak w:

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

Ale uważaj, że dodaje k, M... sufiksy, gdy liczba przekracza 1000 (i wydaje się, że nie ma takiej możliwości ).


Co do swojego tail | awkrozwiązania. Poznaj swoje opcje: -n +0nie przyszło mi do głowy w tej kombinacji.
— towi

2
whoo! pv- kolejne przydatne nowe narzędzie. wielkie dzięki.
— towi

Z grep możesz dodać filtr do swojego strumienia:tail -n +0 -f <my.log> | grep --line-buffered <mystring> | awk '{printf "\r%lu", NR}'
— tombolinux

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

Fajne. Dodaję, END{print ""}aby awkwydrukować nowy wiersz na końcu.
— pLumo,

6

Spróbuj policzyć to z czystym bashbez wc:

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

lub nawet w ten sposób, aby przepisać poprzednią wartość:

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

1

Nie wierzę, że jest coś takiego. Ale powinno być łatwo wymieszać coś w stylu:

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

(Ogólny pomysł przeniesiony z perlfunc(1))


1
Liczba będzie rosła za każdym razem, gdy to zrobisz printf foo >> file. Będziesz musiał policzyć znaki nowego wiersza (jak wc -lma to miejsce w rozwiązaniu powłoki, które zasugerowałem), a nie rekordy zwrócone przez <$fh>. Nie sądzę, że musisz użyć telllub seekwcale.
— Stéphane Chazelas,

<$fh>Odczytuje linię domyślnie nie zapisuje. Cytowana strona podręcznika Perla mówi, aby zrobić to w ten sposób ze względu na możliwie niechętne do współpracy środowisko (może to zależeć od systemu plików, sądzę, że NFS lub inne systemy plików podłączone do sieci mogą wymagać trochę prowokacji).
— vonbrand

Wypróbuj sam, po osiągnięciu końca pliku, <$fh>zwróci rekord, nawet jeśli nie jest zakończony znakiem nowej linii. Więc jeśli perlsiedzi na końcu pliku, a ktoś później to zrobi printf foo >> file, to <$fh>wróci foo(nie wiersz, ponieważ nie jest zakończony znakiem nowego wiersza) i $countbędzie zwiększany, nawet jeśli do pliku nie dodano żadnej dodatkowej linii.
— Stéphane Chazelas,

OP miał monitorować logi zapisywane po jednym wierszu?
— vonbrand

Nie, dlatego Twoje rozwiązanie może nie działać. Na przykład, jeśli aplikacje zapisujące plik zbuforują jego dane wyjściowe, to w danym momencie ostatni wiersz prawdopodobnie nie zostanie zakończony, więc zostanie policzony dwukrotnie.
— Stéphane Chazelas,

0

Kontynuacja rozwiązania opartego na awk: może nie być konieczne wyświetlanie licznika dla każdej linii w dzienniku; tak jest, możesz to zrobić w ten sposób (liczba zmienia się dla każdego 10 wierszy):

tail -n +0 logfile.txt | \
    awk 'a+=1{}a%10==0{printf "\r%lu", a}END{printf "\r%lu", a}'
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.