Como `awk 'NF {p=1} p'` remove linhas em branco do início e do final de um arquivo?

Como `awk 'NF {p=1} p'` remove linhas em branco do início e do final de um arquivo?

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 truese 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 como true. O sinalizador pé inicialmente não inicializado e será avaliado como false, portanto, a priori, nada será impresso.
  • Depois que uma linha não em branco é encontrada ( NFé diferente de zero e é avaliada como true), o bloco de regras {p=1}é inserido e o sinalizador pdefinido como 1. Depois disso, o plado externo do bloco de regras é avaliado como truee quaisquer linhas subsequentes (incluindo a atual, a primeira não em branco) são impressas.

Perceberque, como o sinalizador pnunca é 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 a NR, o contador de linhas global, identificamos a primeira e a última linha não vazia.
  • Na segunda passagem ( FNRagora é menor que NR), 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.

informação relacionada