`awk 'NF {p=1} p'` 如何删除文件开头和结尾的空白行?

`awk 'NF {p=1} p'` 如何删除文件开头和结尾的空白行?

在寻找一种从文件的开头和结尾删除空白行(使用tac)的方法时,我偶然发现了这个:

awk 'NF {p=1} p'

这是如何/为什么有效的?

我理解NFtrue当有任何字段时(如果该行不是空行)。

答案1

这将从头开始删除空白行,但不是从最后开始一个文件的。[注意:此答案是在编辑问题提到的tac]

其工作原理如下:

  • NF是在当前行找到的字段数。如果为零,则意味着该行为空或空白的,即最多包含空格(假设字段分隔符保留其默认值,其中任意数量的连续空格都被视为分隔符)。
  • { ... }如果规则块 ( ) 之外(且不与其关联)的任何条件计算结果为 ,则打印当前行true。该标志p最初未初始化,并且计算结果为false,因此先验不会打印任何内容。
  • 一旦找到非空行(NF非零且计算结果为true),则输入规则块{p=1}并将标志p设置为1。之后,p规则块的外部计算为true,并打印任何后续行(包括当前的第一个非空白行)。

注意由于该标志p永远不会重置,因此第一个非空行之后的任何空行都将被打印而不进行过滤。如果您也想从末尾删除空行,则需要采用两遍方法:

awk 'FNR==NR{if (NF) {if (!first) first=FNR; last=FNR} next}
     FNR>=first && FNR<=last' input.txt input.txt

这将处理文件两次(因此它被指定为操作数两次)

  • 在第一遍中,FNR其中每个文件行计数器等于NR全局行计数器,我们识别第一个和最后一个非空行。
  • 在第二遍(FNR现在小于NR)中,我们仅打印如此标识的第一行和最后一个非空白行之间(并包括)的行。

注意

如中所述斯蒂芬·查泽拉斯的回答,两遍方法仅适用于常规文件。如果您的输入具有不同的性质,请参阅此处提出的解决方案的方法。

答案2

使用此技术从文件的头部和尾部删除空白行:

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

答案3

您的代码的作用以及为什么它只删除输入开头的空白行已经在@AdminBee 的回答例如,但为了完整起见,我将建议一种替代方法来删除前导和尾随空白行,而不必对文件进行两次传递(这仅适用于常规文件,不适用于任意输入)。

awk '
       NF {print saved $0; saved = ""; started = 1; next}
  started {saved = saved $0 ORS}' < file

我们将空白行的打印延迟到我们随后看到的下一个非空白行(前提是我们之前已经看到过至少一个非空白行)。

答案4

如果您不介意破坏要保留的空白行上的任何空格或制表符,这将从开头和结尾删除空白行:

awk 'NF{for(;c;--c)print "";print;x=1;next} x{++c}'

它计算非空行之间出现的空行数,并在每个非空行之前打印那么多空行。

相关内容