Как сделать непрерывный 'wc -l' с текстовыми инструментами GNU?

28

Я знаю конечно что

cat logfile.txt | wc -l
120

скажет мне количество строк в файле.

В то время как

tail -f logfile.txt

покажет мне новые строки, в которые пишет другая программа logfile.txt.

Можно ли объединить оба, так что я получаю непрерывное обновление строки счетчика logfile.txt со стандартными текстовыми утилитами?

Я знаю о

watch wc -l logfile.txt

но я не хочу пересчитывать весь файл каждый раз, это кажется пустой тратой. Каждую секунду или около того потребуется счетчик только с добавлением и, возможно, \rвместо \nконца строки.

towi
источник
1
Является ли ваш файл настолько большим, что пересчет всего является проблемой? С точки зрения отходов: catвыпуск продукции в трубопровод wcтакже является большой тратой !!
Бернхард
Да, это потенциально очень большой.
Towi

Ответы:

36

Может быть:

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

Остерегайтесь того, что он будет выводить число для каждой строки ввода (хотя переопределяет предыдущее значение, если отправлено на терминал).

Или вы можете реализовать это tail -fвручную в оболочке:

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

(обратите внимание, что она выполняет до одной wcи одной sleepкоманды в секунду, которую встроили не все оболочки. С помощью встроенного ksh93while sleepдля получения встроенного wc(по крайней мере, в Debian), вы должны добавить /opt/ast/binперед $PATH(независимо от того, этот каталог существует или нет) или использовать command /opt/ast/bin/wc(не спрашивайте ...)).

Вы можете использовать pv, как в:

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

Но нужно учитывать , что он добавляет k, M... суффиксы , когда число превышает 1000 (и там , кажется, не быть способ вокруг этого ).

Стефан Шазелас
источник
Whow к вашему tail | awkрешению. Знайте свои варианты: -n +0не пришло бы мне в голову в этой комбинации.
Towi
2
Ого! pv- еще один полезный новый инструмент. огромное спасибо.
13
С помощью grep вы можете добавить фильтр в свой поток:tail -n +0 -f <my.log> | grep --line-buffered <mystring> | awk '{printf "\r%lu", NR}'
tombolinux
2
@tombolinux, awkэто расширенный набор grep. tail -n +0 -f file | awk '/mystring/ {printf "\r%lu", ++n}'
Стефан Шазелас,
Круто. Я добавляю, END{print ""}чтобы сделать awkпечать новой строки в конце.
pLumo
6

Попробуйте посчитать с чистым bashбез wc:

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

или даже так, чтобы переписать предыдущее значение:

a=0 ; tail -f file | while read -r line ; do ((a++)) ; echo -ne "\r$a" ; done
порыв
источник
1

Я не верю, что есть что-то подобное. Но это должно быть легко сделать что-то вроде:

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

(Общая идея извлечена из perlfunc(1))

vonbrand
источник
1
Число будет увеличиваться каждый раз, когда вы делаете printf foo >> file. Вам нужно будет посчитать символы новой строки (как wc -lв предложенном мною решении оболочки), а не записи, возвращаемые <$fh>. Я не думаю, что вам нужно использовать tellили seekвообще.
Стефан Шазелас
По <$fh>умолчанию читает строку, а не записи. Упомянутая man-страница Perl говорит, что делать это таким образом ради возможного отказа от сотрудничества (может зависеть от файловой системы, я думаю, NFS или другие сетевые файловые системы могут потребовать немного подталкивания).
vonbrand
Попробуйте сами, по достижении конца файла <$fh>вернете запись, даже если она не завершается символом перевода строки. Так что, если он perlнаходится в конце файла, а кто-то позже делает printf foo >> file, то <$fh>вернется foo(не строка, поскольку она не заканчивается символом новой строки), и $countбудет увеличен, даже если в файл не было добавлено никакой дополнительной строки.
Стефан Шазелас
ОП должен был следить за лог-файлами, записанными по очереди за раз?
vonbrand
Нет, поэтому ваше решение может не сработать. Например, если приложения, записывающие в файл, буферизуют его вывод, то в любой момент времени последняя строка, скорее всего, не будет завершена, поэтому будет учитываться дважды.
Стефан Шазелас
0

Продолжаем решение на основе awk: вам может не понадобиться видеть тикающий счетчик для каждой строки в вашем журнале; в этом случае вы можете получить его следующим образом (число будет меняться для каждых 10 строк):

tail -n +0 logfile.txt | \
    awk 'a+=1{}a%10==0{printf "\r%lu", a}END{printf "\r%lu", a}'
Artyom
источник