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?
text-processing
grep
wc
Raghunath Choudhary
źródło
źródło
grep
wygraną @MichaelJohn w mojej książce.Odpowiedzi:
Jeśli puste linie są tylko na końcu
lub:
źródło
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
:Wyjaśnienie:
/./
adresuje linie dowolnym znakiem, więc/./!
adresuje niepuste linie; w przypadku tychH
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 przezh
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
.źródło
Więcej GNU
tac
/tail -r
opcji:Lub:
Zauważ, że na wyjściu:
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:
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 daje1
na wyjściuprintf 'x\n '
.źródło
Ponieważ faktycznie pytasz o
grep
rozwiązanie , dodaję to, opierając się tylko na GNUgrep
(dobra, również przy użyciu składni powłoki iecho
...):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? (-;
źródło
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
acut
, ale tutaj starałem się ograniczać do siebiegrep
. Możesz to nazwać przewrotnością, ja nazywam sportem. (-;Inne
awk
rozwiązanie Ta odmiana resetuje licznik zak
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ścik==0
.) Na końcu wyprowadzamy liczbę zliczonych linii.Przygotuj plik danych
Policz końcowe puste linie w próbce
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 != ""
.źródło
$0 > ""
? To zastosowania,strcoll()
które byłyby mniej wydajne niż te,$0 != ""
które są używanememcmp()
w wielu implementacjach (POSIX wymagał jednak, aby z niego korzystałstrcoll()
).$0 > ""
może być inaczej$0 != ""
. I tak mam tendencję do traktowaniaawk
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żywaligrep | awk
konstruktów w takich sytuacjach). Jednakże, miał rzucić okiem na to, co zakładam jest definicja POSIX nie widzę żadnego odniesienia do jednejstrcoll()
lubmemcmp()
. 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=963a <= b && a >= b
niekoniecznie jest taka sama jaka == b
. Auć!awk
lubbash
(za jego[[ a < b ]]
operatorów) w en_US.UTF-8 lokalizacjach w systemach GNU na przykład za①
vs②
na przykład (nabash
żaden<
,>
,=
return true dla tych). Prawdopodobnie jest to błąd w definicji tych lokalizacji bardziej niż w bash / awkSolid
awk
+tac
rozwiązanie:Próbka
input.txt
:Akcja:
!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:
źródło
IIUC, następujący skrypt o nazwie wykonałby
count-blank-at-the-end.sh
zadanie:Przykładowe użycie:
Testowałem go
GNU bash
,Android mksh
awksh
.źródło
Alternatywne
Python
rozwiązanie:Przykładowy plik input.txt:
Akcja:
Wyjście:
https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.takewhile
źródło