Procurando uma maneira de remover linhas em branco do início e do final (usando tac
) de um arquivo, me deparei com este:
awk 'NF {p=1} p'
Como/por que isso funciona?
Entendo NF
é apenas true
se houver algum campo (se a linha não for uma linha em branco).
Responder1
Isso removerá as linhas em branco desde o início,mas não do fimde um arquivo.[Aviso: esta resposta foi escrita antes doedite na perguntaque mencionou tac
]
Funciona da seguinte maneira:
NF
é o número de campos encontrados na linha atual. Se for zero, significa que a linha está vazia ouem branco, ou seja, contém no máximo espaços em branco (assumindo que o separador de campos seja deixado em seu valor padrão, onde qualquer número de espaços em branco consecutivos é considerado como separador).- A linha atual é impressa se qualquer condição fora (e não associada a) blocos de regras (
{ ... }
) for avaliada comotrue
. O sinalizadorp
é inicialmente não inicializado e será avaliado comofalse
, portanto, a priori, nada será impresso. - Depois que uma linha não em branco é encontrada (
NF
é diferente de zero e é avaliada comotrue
), o bloco de regras{p=1}
é inserido e o sinalizadorp
definido como1
. Depois disso, op
lado externo do bloco de regras é avaliado comotrue
e quaisquer linhas subsequentes (incluindo a atual, a primeira não em branco) são impressas.
Perceberque, como o sinalizador p
nunca é redefinido, quaisquer linhas em branco após a primeira linha não em branco serão impressas sem filtragem. Se você quiser remover também as linhas em branco do final, será necessária uma abordagem de duas passagens:
awk 'FNR==NR{if (NF) {if (!first) first=FNR; last=FNR} next}
FNR>=first && FNR<=last' input.txt input.txt
Isso processará o arquivo duas vezes (portanto, é especificado duas vezes como operando)
- Na primeira passagem, onde
FNR
, o contador de linhas por arquivo é igual aNR
, o contador de linhas global, identificamos a primeira e a última linha não vazia. - Na segunda passagem (
FNR
agora é menor queNR
), imprimimos apenas linhas entre (e incluindo) a primeira e a última linhas não vazias assim identificadas.
Perceber
Como afirmado noresposta de Stéphane Chazelas, a abordagem de duas passagens funciona apenas com arquivos regulares. Se a sua entrada for de natureza diferente, consulte o método aí proposto para uma solução.
Responder2
Usando esta técnica para remover linhas em branco do início e do fim do arquivo:
awk 'NF {p=1} p' file | # remove blank lines at the file head
tac | # reverse the lines
awk 'NF {p=1} p' | # remove blanks from the "new head"
tac | # re-reverse the file
sponge file # from the `moreutils` package, to overwrite the file
Responder3
O que o seu código faz e por que ele apenas exclui linhas em branco no início da entrada já foi explicado emResposta de @AdminBeepor exemplo, mas aqui para completar, sugerirei um método alternativo para remover linhas em branco iniciais e finais sem ter que fazer duas passagens no arquivo (o que funcionaria apenas para arquivos regulares e não para entradas arbitrárias).
awk '
NF {print saved $0; saved = ""; started = 1; next}
started {saved = saved $0 ORS}' < file
Onde atrasamos a impressão de linhas em branco até a próxima linha não em branco que veremos depois (desde que já tenhamos visto pelo menos uma linha não em branco antes).
Responder4
Caso você não se importe em preencher quaisquer espaços ou tabulações nas linhas em branco que deseja manter, isso removerá as linhas em branco do início e do fim:
awk 'NF{for(;c;--c)print "";print;x=1;next} x{++c}'
Ele conta quantas linhas em branco ocorrem entre linhas não em branco e imprime esse número de linhas vazias antes de cada linha não em branco.