如何使用 awk 删除文件末尾的空行?

如何使用 awk 删除文件末尾的空行?

我想使用删除仅位于文件末尾的所有空行awk

我能够成功找到一种仅使用以下命令删除顶部所有空行的方法:

awk '/^$/ && a!=1 {a=0} !/^$/ {a=1} a==1 {print}' file.txt

然而,我不知道如何扭转它,所以我可以删除底线。我知道我可以只使用上面的命令并将其与管道连接tac,但我更喜欢仅使用命令的直接方法awk(如果可能)。

为了澄清,如果一行“视觉上是空的”,即最多包含空格和/或制表符,则该行被视为“空”。

答案1

awk

由于 awk 按顺序读取文件,从第一行到最后一行,无需外部帮助(例如 Tac),它只能在实际到达文件末尾时判断空行块是否位于文件末尾。

您可以做的是保留一个带有空行的变量(即只有换行符,默认的记录分隔符RS),并在到达非空行时打印这些空行:

awk '/^$/{n=n RS}; /./{printf "%s",n; n=""; print}' file

print n我不明白为什么和之间有区别printf n

print附加输出记录分隔符ORS,默认为换行符)到要打印的表达式。因此,如果你尝试的话,你会得到一个额外的换行符。您也可以使用单个输出语句来编写它,如下所示

awk '/^$/{n=n RS}; /./{printf "%s%s%s",n,$0,RS; n=""}' file

埃德或者前任

要打印输出(就像 Awk 那样),请选择以下任一选项

printf '%s\n' 'a' '' '.' '?.?+1,$d' ',p' 'Q'  | ed -s file
printf '%s\n' 'a' '' '.' '?.?+1,$d' '%p' 'q!' | ex -s file

要直接将更改应用到文件,请选择以下任一选项

printf '%s\n' 'a' '' '.' '?.?+1,$d' 'w' 'q'   | ed -s file
printf '%s\n' 'a' '' '.' '?.?+1,$d' 'x'       | ex -s file

了解发生了什么事。

命令替换

shell 在命令替换中去除尾随换行符。

printf '%s\n' "$(cat file)"

请注意,某些 shell 无法处理大文件,并会出现“参数列表太长”的错误。

灵感来自这个答案

答案2

无论输入来自管道还是文件,这种 1-pass 方法都可以工作,但必须将每个空行块存储在内存中(除非输入中有数十亿个连续的空行,否则这可能不会真正成为问题) ):

awk 'NF{print s $0; s=""; next} {s=s ORS}' file

如果输入是管道,则这种两遍方法将不起作用,但如果输入是问题中所说的文件并且几乎不使用内存,则这种方法将不起作用:

awk 'NR==FNR{if (NF) n=NR; next} FNR>n{exit} 1' file file

上面假设仅包含空格的行被视为“空”。如果这是错误的,则更NF改为/./.

答案3

awk 'length == 0 { ++n; next } { for (i = 1; i <= n; ++i) print ""; n = 0 }; 1' file

或按照评论中的建议缩短,

awk 'length == 0 { ++n; next } { while (n) { print ""; --n } }; 1'

这会跟踪计数器中空行的运行n

每当看到空行 ( length == 0) 时,计数器就会递增,但不会输出任何内容。

当看到非空行时,首先在当前行之前输出适当数量的空行。计数器n也被重置。

这可以避免从文件末尾输出空行。


使用标准sed

sed -n -e :again -e N -e '/[^\n]/!b again' -e p file

这引入了一个显式循环,该循环将行添加到缓冲区,直到其中除了换行符之外还有其他内容。此时,缓冲区被输出。如果输入文件在使用 读取时结束N,则缓冲区中的数据(仅是换行符)将不会输出。

带注释的代码(最初#n关闭默认输出,就像使用一样-n):

#n

# Label to branch to later.
:again

# Append next line of input to buffer
# with a delimiting newline.
N

# Branch (jump) to :again if there's
# only newlines in the buffer.
/[^\n]/!b again

# Output buffer.
p

答案4

co=`awk '!/^$/{x=NR}END{print x}' filename`
co=$(($co+1))
j="$co,$"
sed -i "${j}d" filename

测试并运行良好

相关内容