Encontre e relate números de linha de linhas vazias no arquivo de texto

4

Eu tenho um arquivo de texto contendo mais de 14.000 linhas. Ele contém alguns dados que estou usando para treinamento de dados de reconhecimento de fala.

Eu criei esse arquivo via codificação do java e devido a algum erro semântico algumas das linhas estão vazias. Toda vez que eu corro treinamento dá um erro após cerca de 30 minutos reclamando que existe uma linha vazia.

Existe algum código / script / comando que possa me fornecer uma lista de números de linha com linhas vazias, para que eu possa preencher essas linhas vazias e economizar meu tempo?

O trabalho deve ser como:

Vou inserir um file.txt e ele me dará

line number 1121,1212,1450,13000 and so on ... estão vazios em file.txt

    
por Adnan Ali 06.08.2017 / 20:18

6 respostas

8

Você pode encontrar as linhas vazias e seus números de linha com

grep -E --line-number --with-filename '^$' file.txt  

Um exemplo:

w3@aardvark:~(0)$ grep -E --line-number --with-filename '^$' file.txt
file.txt:1:
file.txt:3:
file.txt:4:
w3@aardvark:~(0)$ cat -n file.txt
     1  
     2  Not empty
     3  
     4  
     5  Not empty
w3@aardvark:~(0)$ 

Se as linhas "vazias" contiverem espaços em branco ou TABs, use:

grep -E --line-number --with-filename '^\s*$' file.txt
    
por waltinator 06.08.2017 / 20:42
8

sed informará o número da linha com o comando = , para que você possa usar essa expressão para relatar números de linhas vazias (linhas sem nada entre ^ (início da linha) e $ (end da linha)):

sed -n '/^$/=' file

Usamos a opção -n para suprimir a impressão do fluxo (números de linha são impressos separadamente das próprias linhas quando usamos = , portanto não há comando p aqui), portanto a única saída é números de linha das linhas correspondentes.

$ sed -n '/^$/=' foo 
1
3
5
7

(se as linhas 1, 3, 5 e 7 estiverem vazias em foo )

Veja um exemplo para mostrar como você pode obter a interação do usuário desejada. Você poderia usar qualquer solução no lugar da expressão sed nessas estruturas ...

$ cat foo

2

4

6

8

Então:

$ read -p "Enter file name: "; echo -e "The following lines are empty in "$REPLY":\n$(sed -n '/^$/=' "$REPLY" | tr '\n' ' ')"
Enter file name: foo
The following lines are empty in foo:
1 3 5 7 

(use tr '\n' ',' para obter vírgulas em vez de espaços)

Você pode salvar como um script (estou nomeando a minha empline ):

#!/bin/bash
read -p "Enter file name: "
echo -e "The following lines are empty in "$REPLY":\n\
$(sed -n '/^$/=' "$REPLY" | tr '\n' ' ')"

Torne o script executável:

chmod u+x empline

Então você pode executá-lo assim

$ ./empline
Enter file name: foo
The following lines are empty in foo:
1 3 5 7 

Você pode ignorar a linha read e substituir "$REPLY" por "" para usar o nome do arquivo como um parâmetro posicional (portanto, execute ./empline foo ). Para simplificar o uso, você poderia criar uma função e adicionar ao final do seu ~/.bashrc :

function empline() {
    echo -e "The following lines are empty in "":\n\
$(sed -n '/^$/=' "" | tr '\n' ' ')"
}

Isso leva o nome do arquivo como argumento:

$ empline foo
The following lines are empty in foo:
1 3 5 7 
    
por Zanna 06.08.2017 / 20:28
7

Usando awk

O método para entrada de vários arquivos (veja o final do post) é o mais robusto.

Entrada de arquivo único:

awk 'BEGIN { printf "Line numbers of empty lines in " ARGV[1] ": " } !NF { printf sep NR ; sep="," } END { printf "\n" }' file.txt

A seção BEGIN é executada antes de o arquivo de entrada ser processado.

ARGV[1] é o nome do arquivo de entrada. Isso corresponde à variável FILENAME do awk, que não funciona na seção BEGIN .

!NF corresponde a linhas que estão em branco ou que contêm apenas separadores de campo. Os separadores de campos padrão são espaços e caracteres de tabulação, portanto, as linhas que contêm apenas espaços e tabulações contam como vazias. NF (sem o ponto de exclamação) corresponde a linhas que contêm dados, e adicionando ! inverte a correspondência.

NR é o número da linha do arquivo de entrada que está sendo avaliado no momento. NR não redefine para 1 se arquivos de entrada adicionais forem especificados na linha de comando.

Para evitar que uma vírgula apareça na frente do primeiro número de linha correspondente, deixe a string sep undefined até depois de imprimir a primeira correspondência.

A seção END é executada depois que o arquivo de entrada é processado. Neste exemplo, ele finaliza a saída de maneira limpa imprimindo um caractere de nova linha no estilo Unix.

Exemplo de saída:

Line numbers of empty lines in file.txt: 8,13,15,20,25,28

É um pouco desleixado usar um nome de string sem primeiro configurá-lo, mesmo que você queira que ele esteja vazio. Você poderia definir explicitamente a string sep como vazia na seção BEGIN :

awk 'BEGIN { sep="" ; printf "Line numbers of empty lines in " ARGV[1] ": " } !NF { printf sep NR ; sep="," } END { printf "\n" }' file.txt

Entrada de vários arquivos:

awk 'FNR==1 && NR>1 { printf "\n" } FNR==1 { sep="" ; printf "Line numbers of empty lines in " FILENAME ": " } !NF { printf sep FNR ; sep="," } END { printf "\n" }' file1.txt file2.txt file3.txt

FNR é semelhante a NR , exceto que o contador de número de linhas FNR é redefinido como 1 no início de cada arquivo.

A seção FNR==1 && NR>1 { printf "\n" } faz com que a saída de cada arquivo seja impressa em uma linha separada. Ele imprime um caractere de nova linha quando a primeira linha de cada arquivo de entrada adicional é processada, mas não para a primeira linha do arquivo primeiro .

Exemplo de saída:

Line numbers of empty lines in file1.txt: 8,13,15,20,25,28
Line numbers of empty lines in file2.txt: 1,2,4,6,7,9,10
Line numbers of empty lines in file3.txt: 3,8,9,11,13,15
    
por Gaultheria 07.08.2017 / 03:14
6

Pure Bash, usando o arquivo de exemplo foo de resposta de Zanna :

i=0
while read line; do
    ((++i))
    if [[ $line == '' ]]; then
        echo $i
    fi
done < foo

Saída:

1
3
5
7

Ou talvez você prefira o equivalente Bash da solução Python usando enumerate() :

cat -n foo | 
    while read -r i line; do
       if [[ $line == '' ]]; then
            echo $i
        fi
    done
    
por wjandrea 06.08.2017 / 20:43
3

perl :

Imprimindo ( printf("%s\n", $.) ) o número da linha, se estiver vazio ( if /^$/ ):

perl -ne 'printf("%s\n", $.) if /^$/' file.txt

python3 :

Iterando as linhas enumeradas ( start == 1 ) do arquivo e imprimindo o número da linha quando estiver vazio:

with open('file.txt') as f:
    for idx, line in enumerate(f, 1):
        if line.rstrip('\n') == "":
            print(idx)
    
por heemayl 07.08.2017 / 05:48
2

Para uma única execução de arquivo:

$ printf "line numbers %s are empty in your file.\n"\
 "$(grep --line-number '^$' file-name | tr ':\n' ', ')"

Quais resultados:

line numbers 2, 5, 7, 9, 10,  are empty in your file.
    
por Ravexina 07.08.2017 / 03:54