У мене в кінці файлу є порожні рядки. Чи можу я grep
рахувати кількість пустих рядків у кінці файлу, при цьому ім'я файлу передається як змінне в сценарії?
grep
@MichaelJohn виграти за чистоту в моїй книзі.
У мене в кінці файлу є порожні рядки. Чи можу я grep
рахувати кількість пустих рядків у кінці файлу, при цьому ім'я файлу передається як змінне в сценарії?
grep
@MichaelJohn виграти за чистоту в моїй книзі.
Відповіді:
Якщо порожні рядки знаходяться лише в кінці
grep -c '^$' myFile
або:
grep -cx '' myFile
grep -cv . myFile
це ще один спосіб його написання (для гравців з кодом). Але я знайшов рішення, grep
якщо в файлі де-небудь є порожні рядки.
grep -cv .
також вважатиме рядки, що містять лише байти, які не утворюють дійсних символів.
Просто для розваги, моторошний 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
.Ще кілька 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 '
.
Оскільки ви насправді просите 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 ".*"
для підрахунку рядків.
Блискуче, чи не так? (-;
tac | grep
спочатку не пусте значення -m -A 42
, а потім мінус одне. Я не впевнений, що є більш ефективним, але ви могли б wc -l | cut -d' ' -f1
замість того, щоб чіпляти порожні рядки?
tac
, wc
і cut
, але тут я намагався обмежитися grep
. Ви можете назвати це химерністю, я називаю це спортом. (-;
Ще одне 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 != ""
.
$0 > ""
? Це використання, strcoll()
яке було б менш ефективним, ніж те, $0 != ""
яке використовується memcmp()
у багатьох реалізаціях (POSIX використовувався для того, щоб вимагати його використання strcoll()
).
$0 > ""
може бути інакше $0 != ""
. Я, як правило, розглядаю awk
як "повільний" оператор (такий, що якщо я знаю, що у мене є великий набір даних як введення даних, і обробка є критичною за часом, я побачу, що я можу зробити, щоб зменшити суму, awk
яку потрібно обробити - я використовували grep | awk
конструкції в таких ситуаціях). Однак, швидко ознайомившись із тим, що я припускаю, є визначення POSIX, я не можу побачити жодної посилання на те strcoll()
чи інше memcmp()
. Що я пропускаю?
strcoll()
== рядки повинні порівнюватися, використовуючи послідовну послідовність зіставлення, характерну для місцевості . Порівняйте з попереднім виданням . Я виховував це. Дивіться також austingroupbugs.net/view.php?id=963
a <= b && a >= b
не обов'язково те саме, що a == b
. Ой!
awk
або bash
(для його [[ a < b ]]
операторів) в en_US.UTF-8 локалей в системах GNU, наприклад , для ①
проти ②
, наприклад (для bash
, жоден з <
, >
, =
повертає істину для тих , хто). Можливо, це помилка у визначенні цих
порахувати кількість послідовних порожніх рядків у кінці файлу
Твердий 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
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
.
Альтернативне Python
рішення:
Зразок input.txt:
$ cat input.txt
aaa
bbb
ccc
$ # command line
Дія:
python -c 'import sys, itertools; f=open(sys.argv[1]);
lines=list(itertools.takewhile(str.isspace, f.readlines()[::-1]));
print(len(lines)); f.close()' input.txt
Вихід:
3
https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.taketake