
У меня есть файл с пустыми строками в конце файла. Могу ли я использовать grep
для подсчета количества пустых строк в конце файла, передавая имя файла как переменную в скрипте?
решение1
Если пустые строкитольков конце
grep -c '^$' myFile
или:
grep -cx '' myFile
решение2
Просто ради забавы, немного жути 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
.
решение3
Еще несколько опций 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 '
.
решение4
Поскольку вы на самом деле проситеgrep
решениеЯ добавляю это, полагаясь только на GNU grep
(ладно, также используя синтаксис оболочки и echo
...):
#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))
Что я здесь делаю? $(grep -c ".*" "$1")
подсчитывает все строки в файле, затем вычитает файл без конечных пустых строк.
И как их получить? $(grep -B42 . "$1"
grep все непустые строки и 42 строки перед ними, так что он выведет все до последней непустой строки, пока не будет более 42 последовательных пустых строк перед непустой строкой. Чтобы избежать этого ограничения, я беру $(grep -cv . "$1")
в качестве параметра для -B
опции, которая является общим количеством пустых строк, поэтому всегда достаточно большим. Таким образом я удалил конечные пустые строки и могу использовать |grep -c ".*"
для подсчета строк.
Гениально, не правда ли? (-;