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?


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

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.

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 '.


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 é? (-;


+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 != "".


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

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.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.