Ho un file con righe vuote alla fine del file. Posso usare grep
per contare il numero di righe vuote alla fine del file con il nome del file passato come variabile nello script?
grep
@MichaelJohn di vincere per purezza nel mio libro.
Ho un file con righe vuote alla fine del file. Posso usare grep
per contare il numero di righe vuote alla fine del file con il nome del file passato come variabile nello script?
grep
@MichaelJohn di vincere per purezza nel mio libro.
Risposte:
Se le righe vuote sono solo alla fine
grep -c '^$' myFile
o:
grep -cx '' myFile
grep -cv . myFile
è un altro modo di scriverlo (per i golfisti del codice). Ma ho trovato una soluzione con grep
se ci sono righe vuote in qualsiasi parte del file.
grep -cv .
conterrebbe anche le righe che contengono solo byte che non formano caratteri validi.
Solo per divertimento, alcuni spettrali sed
:
#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l
Spiegazione:
/./
indirizza le righe con qualsiasi carattere, quindi /./!
indirizza le righe non vuote; per quelli, il H
comando li aggiunge allo spazio di attesa. Pertanto, se per ogni riga vuota abbiamo aggiunto una riga allo spazio di attesa, esiste sempre una riga in più rispetto al numero di righe vuote. Ci penseremo più tardi.//h
il modello vuoto corrisponde all'ultima espressione regolare, che era qualsiasi carattere, quindi qualsiasi riga non vuota viene indirizzata e spostata nello spazio di attesa dal h
comando per "reimpostare" le linee raccolte su 1. Quando verrà aggiunta la riga vuota successiva, ce ne saranno di nuovo due, come previsto.$!d
arresta lo script senza output per ogni tranne l'ultima riga, quindi ulteriori comandi vengono eseguiti solo dopo l'ultima riga. Quindi, qualsiasi riga vuota che abbiamo raccolto nello spazio di attesa si trova alla fine del file. Buona.//d
: Il d
comando viene nuovamente eseguito solo per le righe non vuote. Quindi, se l'ultima riga non era vuota, sed
uscirà senza alcun output. Zero linee. Buona.x
gli scambi trattengono lo spazio e lo spazio del motivo, quindi le linee raccolte si trovano nello spazio del motivo ora per essere elaborate.s/\n//
.wc -l
.Altre GNU tac
/ tail -r
opzioni:
tac file | awk 'NF{exit};END{print NR?NR-1:0}'
O:
tac file | sed -n '/[^[:blank:]]/q;p' | wc -l
Si noti che sull'output di:
printf 'x\n '
Cioè, dove c'è uno spazio extra dopo l'ultima riga completa (che alcuni potrebbero considerare come una riga vuota aggiuntiva, ma dalla definizione POSIX di testo, non è un testo valido), quelli darebbero 0.
POSIXly:
awk 'NF{n=NR};END{print NR-n}' < file
ma ciò significa leggere il file per intero ( tail -r
/ tac
leggerebbe il file all'indietro dalla fine sui file ricercabili). Questo dà 1
sull'output di printf 'x\n '
.
Dato che stai effettivamente chiedendo una grep
soluzione, aggiungo questo basandomi solo su GNU grep
(ok, anche usando la sintassi della shell e echo
...):
#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))
Cosa sto facendo qui? $(grep -c ".*" "$1")
conta tutte le righe nel file, quindi sottraiamo il file senza le righe vuote finali.
E come ottenerli? $(grep -B42 . "$1"
avrebbe grep tutte le righe non vuote e 42 prima di esse, quindi stamperebbe tutto fino all'ultima riga non vuota, purché non vi siano più di 42 righe vuote consecutive prima di una riga non vuota. Per evitare questo limite, prendo $(grep -cv . "$1")
come parametro per l' -B
opzione, che è il numero totale di righe vuote, quindi sempre abbastanza grande. In questo modo ho eliminato le righe vuote finali e posso usarle |grep -c ".*"
per contare le righe.
Fantastico, vero? (-;
tac | grep
quella del primo non vuoto con -m -A 42
, quindi meno uno. Non sono sicuro di quale sia più efficiente, ma potresti anche wc -l | cut -d' ' -f1
invece di afferrare le righe vuote?
tac
, wc
e cut
, ma qui ho cercato di limitarmi a grep
. Puoi chiamarlo perversità, io lo chiamo sport. (-;
Un'altra awk
soluzione. Questa variazione reimposta il contatore k
ogni volta che c'è una linea non vuota. Quindi, ogni riga incrementa il contatore. (Quindi, dopo la prima riga di lunghezza non vuota,. k==0
) Alla fine abbiamo generato il numero di righe che abbiamo contato.
Preparare il file di dati
cat <<'X' >input.txt
aaa
bbb
ccc
X
Contare le righe vuote finali nell'esempio
awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3
In questa definizione, una riga vuota potrebbe contenere spazi o altri caratteri vuoti; è ancora vuoto. Se vuoi davvero contare le righe vuote anziché vuote, cambia NF
per $0 != ""
.
$0 > ""
? Quello utilizza strcoll()
che sarebbe meno efficiente di quello $0 != ""
che utilizza memcmp()
in molte implementazioni (POSIX utilizzato per richiederlo strcoll()
però).
$0 > ""
potrebbe essere diverso $0 != ""
. Tendo a trattare awk
come un operatore "lento" (in modo tale che se so di avere un set di dati di grandi dimensioni come input e l'elaborazione è critica in termini di tempo, vedrò cosa posso fare per ridurre la quantità awk
da elaborare - I hanno usato grep | awk
costrutti in tali situazioni). Tuttavia, avendo avuto un rapido sguardo a quello che presumo è la definizione POSIX non riesco a vedere alcun riferimento a uno strcoll()
o memcmp()
. Cosa mi sto perdendo?
strcoll()
== le stringhe devono essere confrontate usando la sequenza di confronto specifica della locale . Confronta con l' edizione precedente . Sono stato io a sollevarlo. Vedi anche austingroupbugs.net/view.php?id=963
a <= b && a >= b
non è necessariamente la stessa a == b
. Ahia!
awk
o bash
(per i suoi [[ a < b ]]
operatori) en_US.UTF-8 locali sui sistemi GNU, ad esempio, per i ①
vs ②
per esempio (per bash
, nessuno di <
, >
, =
restituire vero per coloro). Probabilmente è un bug nella definizione di quei locali più che in bash / awk
per contare il numero di righe vuote consecutive alla fine del file
Solid awk
+ tac
soluzione:
Campione input.txt
:
$ cat input.txt
aaa
bbb
ccc
$ # command line
L'azione:
awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
!NF
- assicura che la riga corrente sia vuota (non ha campi)NR==++c
- garantire l'ordine consecutivo delle righe vuote. ( NR
- numero di registrazione, ++c
- contatore ausiliario uniformemente incrementato)cnt++
- contatore di righe vuoteIl risultato:
3
IIUC, il seguente script chiamato count-blank-at-the-end.sh
farebbe il lavoro:
#!/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"
Esempio di utilizzo:
$ ./count-blank-at-the-end.sh FILE
4
Ho provato a GNU bash
, Android mksh
e in ksh
.
Python
Soluzione alternativa :
Esempio input.txt:
$ cat input.txt
aaa
bbb
ccc
$ # command line
L'azione:
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
Il risultato:
3
https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.takewhile