Cod*_*oob 2 awk text-processing
我想使用以下命令删除仅位于文件末尾的所有空行 awk
我只能使用以下命令成功找到删除顶部所有空行的方法:
awk '/^$/ && a!=1 {a=0} !/^$/ {a=1} a==1 {print}' file.txt
Run Code Online (Sandbox Code Playgroud)
但是,我不知道如何反转它,因此我可以删除底线。我知道我可以只使用上面的命令并用 管道它tac,但我更喜欢awk只使用命令的直接方法(如果可能的话)。
澄清一下,如果一行“视觉上是空的”,即最多包含空格和/或制表符,则该行被认为是“空的”。
由于 awk 从第一行到最后一行按顺序读取文件,没有外部帮助(例如 Tac),它只能在实际到达文件末尾时确定文件末尾是否有空行块。
您可以做的是保留一个带有空行的变量(即,只有换行符,默认记录分隔符RS)并在遇到非空行时打印这些空行:
awk '/^$/{n=n RS}; /./{printf "%s",n; n=""; print}' file
Run Code Online (Sandbox Code Playgroud)
我不明白为什么
print n和之间有区别printf n。
print将输出记录分隔符(ORS,默认为换行符)附加到要打印的表达式。因此,如果您尝试它,您会得到一个额外的换行符。您也可以使用单个输出语句编写它,如
awk '/^$/{n=n RS}; /./{printf "%s%s%s",n,$0,RS; n=""}' file
Run Code Online (Sandbox Code Playgroud)
要打印输出(就像 Awk 所做的那样),请选择以下任一
printf '%s\n' 'a' '' '.' '?.?+1,$d' ',p' 'Q' | ed -s file
printf '%s\n' 'a' '' '.' '?.?+1,$d' '%p' 'q!' | ex -s file
Run Code Online (Sandbox Code Playgroud)
要将更改直接应用于文件,请选择以下任一
printf '%s\n' 'a' '' '.' '?.?+1,$d' 'w' 'q' | ed -s file
printf '%s\n' 'a' '' '.' '?.?+1,$d' 'x' | ex -s file
Run Code Online (Sandbox Code Playgroud)
Shell 在命令替换中去除尾随的换行符。
printf '%s\n' "$(cat file)"
Run Code Online (Sandbox Code Playgroud)
请注意,某些 shell 无法处理大文件,并且会出现“参数列表太长”的错误。
受到这个答案的启发。
awk 'length == 0 { ++n; next } { for (i = 1; i <= n; ++i) print ""; n = 0 }; 1' file
Run Code Online (Sandbox Code Playgroud)
或缩短,如评论中所建议,
awk 'length == 0 { ++n; next } { while (n) { print ""; --n } }; 1'
Run Code Online (Sandbox Code Playgroud)
这会跟踪计数器中空行的运行情况n。
每当看到空行 ( length == 0) 时,计数器都会增加但不输出任何内容。
当看到非空行时,在当前行之前先输出适当数量的空行。计数器n也被复位。
这避免了从文件末尾输出空行。
使用标准sed:
sed -n -e :again -e N -e '/[^\n]/!b again' -e p file
Run Code Online (Sandbox Code Playgroud)
这引入了一个显式循环,该循环向缓冲区添加行,直到其中包含除换行符以外的其他内容。此时,缓冲区被输出。如果输入文件在读取时结束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
Run Code Online (Sandbox Code Playgroud)
无论输入是来自管道还是文件,这种 1-pass 方法都可以工作,但必须将每个空行块存储在内存中(除非您的输入中有数十亿个连续的空行,否则这可能不是真正的问题):
awk 'NF{print s $0; s=""; next} {s=s ORS}' file
Run Code Online (Sandbox Code Playgroud)
如果输入是管道,则这种 2-pass 方法将不起作用,但如果输入是您在问题中所说的文件并且几乎不使用内存,则这种方法会起作用:
awk 'NR==FNR{if (NF) n=NR; next} FNR>n{exit} 1' file file
Run Code Online (Sandbox Code Playgroud)
以上假设仅包含空格的行被视为“空”。如果那是错误的,则更NF改为/./.