Contare il numero di righe vuote alla fine del file


11

Ho un file con righe vuote alla fine del file. Posso usare grepper contare il numero di righe vuote alla fine del file con il nome del file passato come variabile nello script?


contare il numero di righe vuote consecutive ?
RomanPerekhrest,

2
@RomanPerekhrest Direi di sì, altrimenti non sarebbero "alla fine del file"?
Sparhawk,

'grep -cv -P' \ S 'nomefile' conterà il numero totale di righe vuote nel file. Il numero alla fine mi sta solo tassando!
MichaelJohn,

OP ha chiesto a grep@MichaelJohn di vincere per purezza nel mio libro.
Bu5hman,

2
@ bu5hman Ma (come ammette) non risponde alla domanda. Nemmeno il tuo, davvero.
Sparhawk,

Risposte:


11

Se le righe vuote sono solo alla fine

grep  -c '^$' myFile

o:

grep -cx '' myFile

Picchiato
all'editing in

grep -cv . myFileè un altro modo di scriverlo (per i golfisti del codice). Ma ho trovato una soluzione con grepse ci sono righe vuote in qualsiasi parte del file.
Philippos,

2
@Philippos, grep -cv .conterrebbe anche le righe che contengono solo byte che non formano caratteri validi.
Stéphane Chazelas,

11

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 Hcomando 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.
  • //hil 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 hcomando per "reimpostare" le linee raccolte su 1. Quando verrà aggiunta la riga vuota successiva, ce ne saranno di nuovo due, come previsto.
  • $!darresta 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 dcomando viene nuovamente eseguito solo per le righe non vuote. Quindi, se l'ultima riga non era vuota, seduscirà 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.
  • Ma ricordiamo che esiste una riga in eccesso, quindi la riduciamo rimuovendo una nuova riga con s/\n//.
  • Ecco! Il numero di righe corrisponde al numero di righe vuote alla fine (nota che la prima riga non sarà vuota, ma chi se ne frega), quindi possiamo contarle wc -l.

8

Altre GNU tac/ tail -ropzioni:

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/ tacleggerebbe il file all'indietro dalla fine sui file ricercabili). Questo dà 1sull'output di printf 'x\n '.


6

Dato che stai effettivamente chiedendo una grepsoluzione, 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' -Bopzione, 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? (-;


+1 perché sebbene sia un codice orribile, tecnicamente risponde alla domanda come posta e non posso sopportare di
annotarti

Grepmeister. Non siamo degni.
Bu5hman,

+1 per la perversità. Un'altra opzione (forse più veloce?) Sarebbe tac | grepquella 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' ' -f1invece di afferrare le righe vuote?
Sparhawk,

Sì, certo, puoi fare molte cose con tac, wce cut, ma qui ho cercato di limitarmi a grep. Puoi chiamarlo perversità, io lo chiamo sport. (-;
Philippos,

5

Un'altra awksoluzione. Questa variazione reimposta il contatore kogni 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 NFper $0 != "".


Perché $0 > ""? Quello utilizza strcoll()che sarebbe meno efficiente di quello $0 != ""che utilizza memcmp()in molte implementazioni (POSIX utilizzato per richiederlo strcoll()però).
Stéphane Chazelas,

@ StéphaneChazelas Non ho considerato che $0 > ""potrebbe essere diverso $0 != "". Tendo a trattare awkcome 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à awkda elaborare - I hanno usato grep | awkcostrutti 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?
roaima,

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
Stéphane Chazelas

@ StéphaneChazelas un'implementazione in cui a <= b && a >= bnon è necessariamente la stessa a == b. Ahia!
roaima,

Questo è il caso di GNU awko 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
Stéphane Chazelas,

2

per contare il numero di righe vuote consecutive alla fine del file

Solid awk+ tacsoluzione:

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 vuote

Il risultato:

3

1

IIUC, il seguente script chiamato count-blank-at-the-end.shfarebbe 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 mkshe in ksh.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.