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