Подсчитайте количество пустых строк в конце файла

11

У меня есть файл с пустыми строками в конце файла. Можно ли использовать grepдля подсчета количества пустых строк в конце файла с именем файла, передаваемым в сценарии как переменная?

Рагхунат Чоудхари
источник
посчитать количество последовательных пустых строк ?
РоманПерехрест
2
@RomanPerekhrest Я бы так сказал, иначе они не были бы "в конце файла"?
Sparhawk
'grep -cv -P' \ S 'filename' будет подсчитывать общее количество пустых строк в файле. Число в конце только облагораживает мой мозг!
MichaelJohn
ОП попросил grep@MichaelJohn за чистоту в моей книге.
bu5hman
2
@ bu5hman Но (как он признается) не отвечает на вопрос. На самом деле не ваш.
Sparhawk

Ответы:

11

Если пустые строки только в конце

grep  -c '^$' myFile

или же:

grep -cx '' myFile
bu5hman
источник
Избитый на редактирование секундами, черт побери
bu5hman
grep -cv . myFileэто еще один способ написать это (для игроков в гольф код). Но я нашел решение, grepесли в файле есть пустые строки.
Филиппос
2
@Philippos grep -cv .также будет считать строки, содержащие только байты, которые не образуют допустимых символов.
Стефан
11

Просто для удовольствия, некоторые привидение sed:

#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l

Объяснение:

  • /./адреса строк с любым символом, поэтому /./!адреса непустые строки; для них Hкоманда добавляет их в область ожидания. Таким образом, если для каждой пустой строки мы добавили одну строку в пространство удержания, всегда будет на одну строку больше, чем количество пустых строк. Мы позаботимся об этом позже.
  • //hпустой шаблон соответствует последнему регулярному выражению, которое было любым символом, поэтому любая непустая строка адресуется и перемещается в пространство удержания hкомандой, чтобы «сбросить» собранные строки до 1. Когда следующая пустая строка будет добавлена, снова будет два, как и ожидалось.
  • $!dостанавливает сценарий без вывода для каждой строки, кроме последней, поэтому дальнейшие команды выполняются только после последней строки. Таким образом, все пустые строки, которые мы собрали в области хранения, находятся в конце файла. Хорошо.
  • //d: Команда dснова выполняется только для непустых строк. Так что, если последняя строка не была пустой, sedвыйдет без вывода. Ноль линий. Хорошо.
  • x обмены содержат пространство и пространство шаблона, поэтому собранные строки теперь находятся в пространстве шаблона для обработки.
  • Но мы помним, что слишком много одной строки, поэтому мы уменьшаем ее, удаляя одну новую строку с помощью s/\n//.
  • Вуаля! Количество строк соответствует количеству пустых строк в конце (обратите внимание, что первая строка не будет пустой, но кого это волнует), поэтому мы можем сосчитать их wc -l.
Philippos
источник
8

Еще несколько GNU tac/ tail -rопций:

tac file | awk 'NF{exit};END{print NR?NR-1:0}'

Или:

tac file | sed -n '/[^[:blank:]]/q;p' | wc -l

Обратите внимание, что на выходе:

printf 'x\n '

То есть, если после последней полной строки есть дополнительный пробел (который некоторые могут рассматривать как лишнюю пустую строку, но по определению текста POSIX это недопустимый текст), они дадут 0.

POSIXly:

awk 'NF{n=NR};END{print NR-n}' < file

но это означает, что файл будет прочитан полностью ( tail -r/ tacбудет считывать файл в обратном направлении с конца для поиска файлов). Это дает 1на выходе printf 'x\n '.

Стефан Шазелас
источник
6

Поскольку вы на самом деле запрашиваете grepрешение, я добавляю это, полагаясь только на GNU grep(хорошо, также используя синтаксис оболочки и echo...):

#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))

Что я здесь делаю? $(grep -c ".*" "$1")считает все строки в файле, затем вычитает файл без конечных пустых строк.

И как их получить? $(grep -B42 . "$1"будет обрабатывать все непустые строки и 42 строки перед ними, поэтому он будет печатать все до последней непустой строки, если перед непустой строкой находится не более 42 последовательных пустых строк. Чтобы избежать этого ограничения, я принимаю $(grep -cv . "$1")в качестве параметра для -Bопции, которая является общим количеством пустых строк, поэтому всегда достаточно большой. Таким образом, я убрал конечные пустые строки и могу использовать их |grep -c ".*"для подсчета строк.

Блестящий, не правда ли? (-;

Philippos
источник
+1, потому что, хотя это ужасный код, он технически отвечает на вопрос в том виде, в котором он был задан, и я не могу вас отметить ;-)
roaima
Grepmeister. Мы не достойны.
bu5hman
+1 за порочность. Другим (возможно, более быстрым?) Вариантом будет tac | grepпервый непустой с -m -A 42, затем минус один. Я не уверен, что является более эффективным, но вы также могли бы wc -l | cut -d' ' -f1вместо того, чтобы вырезать пустые строки?
Sparhawk
Да, конечно, вы можете многое сделать tac, wcи cut, но здесь я пытался ограничиться grep. Вы можете назвать это извращением, я называю это спортом. (-;
Philippos
5

Другое awkрешение. Этот вариант сбрасывает счетчик kкаждый раз, когда появляется непустая строка. Затем каждая строка увеличивает счетчик. (Итак, после первой непустой строки длины k==0.) В конце мы выводим количество пересчитанных нами строк.

Подготовьте файл данных

cat <<'X' >input.txt
aaa

bbb
ccc



X

Подсчитайте конечные пустые строки в образце

awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3

В этом определении пустая строка может содержать пробелы или другие пустые символы; это все еще пусто Если вы действительно хотите считать пустые строки, а не пустые, измените NFна $0 != "".

roaima
источник
Почему $0 > ""? Использует то, strcoll()что было бы менее эффективно, чем то, $0 != ""которое используется memcmp()во многих реализациях (POSIX раньше требовал его использования, strcoll()хотя).
Стефан
@ StéphaneChazelas Я не думал, что это $0 > ""может отличаться $0 != "". В awkлюбом случае я склонен относиться к «медленным» операторам (например, если я знаю, что у меня большой ввод данных в качестве входных данных, а обработка критична по времени, я посмотрю, что можно сделать, чтобы уменьшить объем awkобработки - я использовали grep | awkконструкции в таких ситуациях). Тем не менее, имея быстрый взгляд на то , что я предполагаю , что это определение POSIX я не вижу каких - либо ссылок на любой strcoll()или memcmp(). Что мне не хватает?
Ройма
strcoll()== строки должны сравниваться с использованием последовательности сопоставления для конкретной локали . Сравните с предыдущим изданием . Я был тем, кто поднял это. См. Также austingroupbugs.net/view.php?id=963
Стефан
@ StéphaneChazelas реализация, где a <= b && a >= bне обязательно совпадает с a == b. Ой!
роайма
Это случай GNU awkили bash(для его [[ a < b ]]операторов) в en_US.UTF-8 локалей в системах GNU, например , для против , например (для bash, ни один из <, >, =возвращает истину для тех , кто). Возможно, это ошибка в определении этих локалей больше, чем в bash / awk
Стефан
2

подсчитать количество последовательных пустых строк в конце файла

Твердый awk+ tacраствор:

Образец input.txt:

$ cat input.txt
aaa

bbb
ccc



$  # command line 

Действие:

awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
  • !NF- гарантирует, что текущая строка пуста (не имеет полей)
  • NR==++c- обеспечение последовательного порядка пустых строк. ( NR- номер записи, ++c- равномерно увеличенный вспомогательный счетчик)
  • cnt++- счетчик пустых строк

Выход:

3
RomanPerekhrest
источник
1

IIUC, следующий скрипт вызвал count-blank-at-the-end.shбы работу:

#!/usr/bin/env sh

count=$(tail -n +"$(grep . "$1" -n | tail -n 1 | cut -d: -f1)" "$1" | wc -l)
num_of_blank_lines=$((count - 1))

printf "%s\n" "$num_of_blank_lines"

Пример использования:

$ ./count-blank-at-the-end.sh FILE
4

Я тестировал его в GNU bash, Android mkshи ksh.

Аркадиуш Драбчик
источник