Contar o número de linhas em branco no final do arquivo

11

Eu tenho um arquivo com linhas em branco no final do arquivo. Posso usar greppara contar o número de linhas em branco no final do arquivo com o nome do arquivo sendo passado como variável no script?

Raghunath Choudhary
fonte
contar o número de linhas em branco consecutivas ?
RomanPerekhrest
2
@RomanPerekhrest eu diria que sim, caso contrário eles não estariam "no final do arquivo"?
Sparhawk
'grep -cv -P' \ S 'filename' contará o número total de linhas em branco no arquivo. O número no final está taxando meu cérebro!
Michaeljohn
A OP pediu grep@MichaelJohn vence pela pureza no meu livro.
bu5hman
2
@ bu5hman Mas (como ele admite) não responde à pergunta. Nem o seu, realmente.
Sparhawk

Respostas:

11

Se as linhas em branco estiverem apenas no final

grep  -c '^$' myFile

ou:

grep -cx '' myFile
bu5hman
fonte
Espancado até a edição por segundos, caramba
bu5hman
grep -cv . myFileé outra maneira de escrevê-lo (para jogadores de código). Mas eu encontrei uma solução com grepse houver linhas vazias em qualquer lugar do arquivo.
Philippos
2
@ Philippos, grep -cv .também contaria as linhas que contêm apenas bytes que não formam caracteres válidos.
Stéphane Chazelas
11

Apenas por diversão, alguns assustadores sed:

#!/bin/sh
sed '/./!H;//h;$!d;//d;x;s/\n//' "$1" | wc -l

Explicação:

  • /./endereça linhas com qualquer caractere; portanto, /./!endereça linhas não vazias; para aqueles, o Hcomando anexa-os ao espaço de espera. Portanto, se para cada linha vazia adicionamos uma linha ao espaço de espera, sempre há mais uma linha que o número de linhas vazias. Nós cuidaremos disso mais tarde.
  • //ho padrão vazio corresponde à última expressão regular, que era qualquer caractere; portanto, qualquer linha não vazia é endereçada e movida para o espaço de espera pelo hcomando para "redefinir" as linhas coletadas para 1. Quando a próxima linha vazia for anexada, haverá dois novamente, conforme o esperado.
  • $!dinterrompe o script sem saída para todas as linhas, exceto a última, para que outros comandos sejam executados somente após a última linha. Portanto, quaisquer linhas vazias que coletamos no espaço de espera estão no final do arquivo. Boa.
  • //d: O dcomando é novamente executado apenas para linhas não vazias. Portanto, se a última linha não estiver vazia, sedsairá sem nenhuma saída. Zero linhas. Boa.
  • x as trocas mantêm espaço e espaço padrão, portanto as linhas coletadas estão no espaço padrão agora para serem processadas.
  • Mas lembramos que há uma linha a mais, então a reduzimos removendo uma nova linha com s/\n//.
  • Voilà! O número de linhas corresponde ao número de linhas vazias no final (observe que a primeira linha não estará vazia, mas quem se importa), para que possamos contá-las wc -l.
Philippos
fonte
8

Mais algumas opções tac/ GNU tail -r:

tac file | awk 'NF{exit};END{print NR?NR-1:0}'

Ou:

tac file | sed -n '/[^[:blank:]]/q;p' | wc -l

Observe que na saída de:

printf 'x\n '

Ou seja, onde há um espaço extra após a última linha completa (que alguns poderiam considerar como uma linha em branco extra, mas pela definição de texto POSIX, não é um texto válido), esses dariam 0.

POSIXly:

awk 'NF{n=NR};END{print NR-n}' < file

mas isso significa ler o arquivo na íntegra ( tail -r/ tacleria o arquivo para trás a partir do final em arquivos pesquisáveis). Isso dá 1a saída de printf 'x\n '.

Stéphane Chazelas
fonte
6

Como você está realmente pedindo uma grepsolução, eu adiciono esta grepusando apenas o GNU (ok, também usando a sintaxe do shell e echo...):

#!/bin/sh
echo $(( $(grep -c "" "$1") - $(grep -B$(grep -cv . "$1") . "$1" |grep -c "") ))

O que estou fazendo aqui? $(grep -c ".*" "$1")conta todas as linhas do arquivo e subtraímos o arquivo sem as linhas vazias à direita.

E como conseguir isso? $(grep -B42 . "$1"grep todas as linhas não vazias e 42 linhas antes delas, para imprimir tudo até a última linha não vazia, desde que não haja mais de 42 linhas vazias consecutivas antes de uma linha não vazia. Para evitar esse limite, tomo $(grep -cv . "$1")como parâmetro para a -Bopção, que é o número total de linhas vazias, portanto sempre grande o suficiente. Dessa maneira, retirei as linhas vazias à direita e posso usá |grep -c ".*"-las para contar as linhas.

Brilhante, não é? (-;

Philippos
fonte
+1 porque apesar de que é o código horrível, tecnicamente responde à pergunta como pediu e eu não posso suportar a marcá-lo para baixo ;-)
roaima
Grepmeister. Nós não somos dignos.
bu5hman
+1 para a perversidade. Outra opção (possivelmente mais rápida?) Seria ir tac | greppara o primeiro sem espaço em branco -m -A 42e depois para menos um. Não tenho certeza do que é mais eficiente, mas você também pode, em wc -l | cut -d' ' -f1vez de cumprimentar as linhas em branco?
Sparhawk
Sim, claro, você pode fazer muitas coisas com tac, wce cut, mas aqui tentei me restringir grep. Você pode chamar isso de perversidade, eu chamo de esporte. (-;
Philippos
5

Outra awksolução. Essa variação redefine o contador ksempre que houver uma linha que não esteja em branco. Então, cada linha incrementa o contador. (Então, após a primeira linha de comprimento sem espaço em branco k==0,.) No final, produzimos o número de linhas que contamos.

Prepare o arquivo de dados

cat <<'X' >input.txt
aaa

bbb
ccc



X

Contar as linhas em branco à direita na amostra

awk 'NF {k=-1}; {k++}; END {print k+0}' input.txt
3

Nesta definição, uma linha em branco pode conter espaços ou outros caracteres em branco; ainda está em branco. Se você realmente deseja contar linhas vazias em vez de linhas em branco, mude NFpara $0 != "".

roaima
fonte
Por que $0 > ""? Os usos strcoll()que seriam menos eficientes do $0 != ""que os usados memcmp()em muitas implementações (o POSIX exigia que fosse usado strcoll()).
Stéphane Chazelas
@ StéphaneChazelas Eu não considerei isso $0 > ""diferente $0 != "". Eu costumo tratar awkcomo um operador "lento" de qualquer maneira (de modo que, se eu souber que tenho um grande conjunto de dados como entrada e o processamento for muito demorado, verei o que posso fazer para reduzir a quantidade awka processar - I usaram grep | awkconstruções nessas situações). No entanto, tendo examinado rapidamente o que presumo ser a definição POSIX, não vejo nenhuma referência a um strcoll()ou a outro memcmp(). o que estou perdendo?
roaima
strcoll()== as seqüências de caracteres devem ser comparadas usando a sequência de intercalação específica da localidade . Compare com a edição anterior . Fui eu quem falou disso. Veja também austingroupbugs.net/view.php?id=963
Stéphane Chazelas
@ StéphaneChazelas uma implementação onde a <= b && a >= bnão é necessariamente o mesmo que a == b. Ai!
roaima
Esse é o caso de GNU awkou bash(para os seus [[ a < b ]]operadores) em en_US.UTF-8 localidades em sistemas GNU para instância para vs , por exemplo (para bash, nenhum <, >, =retornar verdadeiro para aqueles). Indiscutivelmente é um bug na definição dessas localidades a mais que em bash / awk
Stéphane Chazelas
2

para contar o número de linhas em branco consecutivas no final do arquivo

Solução sólida awk+ tac:

Amostra input.txt:

$ cat input.txt
aaa

bbb
ccc



$  # command line 

A acção:

awk '!NF{ if (NR==++c) { cnt++ } else exit }END{ print int(cnt) }' <(tac input.txt)
  • !NF- garante que a linha atual esteja vazia (sem campos)
  • NR==++c- garantir a ordem consecutiva de linhas em branco. ( NR- número do registro, ++c- contador auxiliar uniformemente aumentado)
  • cnt++- contador de linhas em branco

A saída:

3
RomanPerekhrest
fonte
1

IIUC, o seguinte script chamado count-blank-at-the-end.shfaria o trabalho:

#!/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"

Exemplo de uso:

$ ./count-blank-at-the-end.sh FILE
4

Eu testei-o em GNU bash, Android mkshe em ksh.

Arkadiusz Drabczyk
fonte