Mam plik z pustymi liniami na końcu pliku. Czy mogę użyć grep
do zliczenia liczby pustych linii na końcu pliku, przy czym nazwa pliku jest przekazywana jako zmienna w skrypcie?
grep
wygraną @MichaelJohn w mojej książce.
Mam plik z pustymi liniami na końcu pliku. Czy mogę użyć grep
do zliczenia liczby pustych linii na końcu pliku, przy czym nazwa pliku jest przekazywana jako zmienna w skrypcie?
grep
wygraną @MichaelJohn w mojej książce.
Odpowiedzi:
Jeśli puste linie są tylko na końcu
grep -c '^$' myFile
lub:
grep -cx '' myFile
grep -cv . myFile
jest innym sposobem na napisanie go (dla golfistów kodowych). Ale znalazłem rozwiązanie, grep
jeśli gdziekolwiek w pliku są puste linie.
grep -cv .
zlicza również wiersze zawierające tylko bajty, które nie tworzą prawidłowych znaków.
Dla zabawy, trochę upiorów sed
:
#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l
Wyjaśnienie:
/./
adresuje linie dowolnym znakiem, więc /./!
adresuje niepuste linie; w przypadku tych H
poleceń polecenie dołącza je do miejsca wstrzymania. Zatem jeśli dla każdej pustej linii dodamy jedną linię do przestrzeni wstrzymania, zawsze jest o jedną linię więcej niż liczba pustych linii. Zajmiemy się tym później.//h
pusty wzorzec pasuje do ostatniego wyrażenia regularnego, którym był dowolny znak, więc każda niepusta linia jest adresowana i przenoszona do miejsca wstrzymania przez h
polecenie „zresetowania” zebranych linii do 1. Gdy zostanie dodany następny pusty wiersz, będą dwa, zgodnie z oczekiwaniami.$!d
zatrzymuje skrypt bez wyjścia dla każdego oprócz ostatniego wiersza, więc dalsze polecenia są wykonywane tylko po ostatnim wierszu. Więc wszystkie puste linie, które zebraliśmy w przestrzeni wstrzymania, znajdują się na końcu pliku. Dobrze.//d
: d
Polecenie jest ponownie wykonywane tylko dla niepustych linii. Więc jeśli ostatni wiersz nie był pusty, sed
wyjdzie bez żadnego wyjścia. Zero linii. Dobrze.x
Wymiany przechowują przestrzeń i przestrzeń wzoru, więc zebrane linie znajdują się teraz w przestrzeni wzoru, która ma zostać przetworzona.s/\n//
.wc -l
.Więcej GNU tac
/ tail -r
opcji:
tac file | awk 'NF{exit};END{print NR?NR-1:0}'
Lub:
tac file | sed -n '/[^[:blank:]]/q;p' | wc -l
Zauważ, że na wyjściu:
printf 'x\n '
Oznacza to, że po ostatnim pełnym wierszu znajduje się dodatkowa spacja (którą niektórzy mogą uznać za dodatkową pustą linię, ale według definicji POSIX tekstu nie jest poprawnym tekstem), to dają 0.
POSIXly:
awk 'NF{n=NR};END{print NR-n}' < file
ale to oznacza odczytanie pliku w całości ( tail -r
/ tac
odczytałby plik do tyłu od końca na plikach, które można zobaczyć). To daje 1
na wyjściu printf 'x\n '
.
Ponieważ faktycznie pytasz o grep
rozwiązanie , dodaję to, opierając się tylko na GNU grep
(dobra, również przy użyciu składni powłoki i echo
...):
#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))
Co ja tutaj robię? $(grep -c ".*" "$1")
zlicza wszystkie linie w pliku, następnie odejmujemy plik bez końcowych pustych linii.
I jak je zdobyć? $(grep -B42 . "$1"
grepuje wszystkie niepuste linie i 42 linie przed nimi, więc wypisze wszystko do ostatniej niepustej linii, o ile przed niepustą linią nie będzie więcej niż 42 kolejnych pustych linii. Aby uniknąć tego limitu, biorę $(grep -cv . "$1")
jako parametr dla -B
opcji, która jest całkowitą liczbą pustych linii, więc zawsze wystarczająco dużą. W ten sposób usunąłem końcowe puste linie i mogę ich użyć |grep -c ".*"
do zliczenia linii.
Genialne, prawda? (-;
tac | grep
pierwsze niepuste z -m -A 42
, a następnie minus jedna. Nie jestem pewien, która z nich jest bardziej wydajna, ale możesz też wc -l | cut -d' ' -f1
zamiast wstawiać puste linie?
tac
, wc
a cut
, ale tutaj starałem się ograniczać do siebie grep
. Możesz to nazwać przewrotnością, ja nazywam sportem. (-;
Inne awk
rozwiązanie Ta odmiana resetuje licznik za k
każdym razem, gdy pojawia się niepusta linia. Następnie każda linia zwiększa licznik. (Tak więc po pierwszej niepustej linii długości k==0
.) Na końcu wyprowadzamy liczbę zliczonych linii.
Przygotuj plik danych
cat <<'X' >input.txt
aaa
bbb
ccc
X
Policz końcowe puste linie w próbce
awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3
W tej definicji pusty wiersz może zawierać spacje lub inne puste znaki; wciąż jest pusty. Jeśli naprawdę chcesz liczyć puste linie zamiast pustych linii, zmień NF
na $0 != ""
.
$0 > ""
? To zastosowania, strcoll()
które byłyby mniej wydajne niż te, $0 != ""
które są używane memcmp()
w wielu implementacjach (POSIX wymagał jednak, aby z niego korzystał strcoll()
).
$0 > ""
może być inaczej $0 != ""
. I tak mam tendencję do traktowania awk
jako „powolnego” operatora (na przykład, jeśli wiem, że mam duży zestaw danych jako danych wejściowych, a przetwarzanie ma krytyczne znaczenie dla czasu, zobaczę, co mogę zrobić, aby zmniejszyć ilość awk
przetwarzanych danych - ja używali grep | awk
konstruktów w takich sytuacjach). Jednakże, miał rzucić okiem na to, co zakładam jest definicja POSIX nie widzę żadnego odniesienia do jednej strcoll()
lub memcmp()
. czego mi brakuje?
strcoll()
== ciągi należy porównać przy użyciu specyficznej dla danego regionu sekwencji zestawiania . Porównaj z poprzednią edycją . To ja to wychowywałem. Zobacz także austingroupbugs.net/view.php?id=963
a <= b && a >= b
niekoniecznie jest taka sama jak a == b
. Auć!
awk
lub bash
(za jego [[ a < b ]]
operatorów) w en_US.UTF-8 lokalizacjach w systemach GNU na przykład za ①
vs ②
na przykład (na bash
żaden <
, >
, =
return true dla tych). Prawdopodobnie jest to błąd w definicji tych lokalizacji bardziej niż w bash / awk
policzyć liczbę kolejnych pustych linii na końcu pliku
Solid awk
+ tac
rozwiązanie:
Próbka input.txt
:
$ cat input.txt
aaa
bbb
ccc
$ # command line
Akcja:
awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
!NF
- zapewnia, że bieżąca linia jest pusta (nie ma pól)NR==++c
- zapewnienie kolejności pustych wierszy. ( NR
- numer rekordu, ++c
- równomiernie zwiększany licznik pomocniczy)cnt++
- licznik pustych liniiWyjście:
3
IIUC, następujący skrypt o nazwie wykonałby count-blank-at-the-end.sh
zadanie:
#!/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"
Przykładowe użycie:
$ ./count-blank-at-the-end.sh FILE
4
Testowałem go GNU bash
, Android mksh
aw ksh
.
Alternatywne Python
rozwiązanie:
Przykładowy plik input.txt:
$ cat input.txt
aaa
bbb
ccc
$ # command line
Akcja:
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
Wyjście:
3
https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.takewhile