在寻找一种从文件的开头和结尾删除空白行(使用tac
)的方法时,我偶然发现了这个:
awk 'NF {p=1} p'
这是如何/为什么有效的?
我理解NF
仅true
当有任何字段时(如果该行不是空行)。
答案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}'
它计算非空行之间出现的空行数,并在每个非空行之前打印那么多空行。