我有一个样本数据集:
1
2
3
4
5
6
Run Code Online (Sandbox Code Playgroud)
通过以下awk命令成功将其解析为所需的输出
awk 'ORS=NR%3?FS:RS'
1 2 3
4 5 6
Run Code Online (Sandbox Code Playgroud)
您能否提供此命令的解释?我无法将各个部分放在一起。
据我了解:
ORS =输出记录分隔符-这就是我们希望RS成为最终输出的原因,它是3列的行
NR%3 =我们要将数据分组为3个元素的行
?FS:RS -不确定如何适合命令。
谢谢。
%是模运算符(请参阅https://en.wikipedia.org/wiki/Modulo_operation),并且NR%3?FS:RS是三元表达式(请参阅https://en.wikipedia.org/wiki/%3F:)。这些都是许多编程语言中的常见构造,它们并非特定于awk。有关ORS,NR,FS和RS的含义,请参见awk手册页。
运行此命令,以在执行命令之前和之后查看代码中变量的值:
$ cat tst.awk
BEGIN {
printf "%s=\"%s\"\n", "RS", RS
printf "%s=\"%s\"\n", "FS", FS
}
{
printf "---\n"
printf "%s=\"%s\"\n", "$0", $0
printf "%s=\"%s\"\n", "NR", NR
printf "%s=\"%s\"\n", "NR%3", NR%3
printf "before) %s=\"%s\"\n", "ORS", ORS
ORS = (NR%3 ? FS : RS)
printf "after) %s=\"%s\"\n", "ORS", ORS
}
Run Code Online (Sandbox Code Playgroud)
。
$ awk -f tst.awk file
RS="
"
FS=" "
---
$0="1"
NR="1"
NR%3="1"
before) ORS="
"
after) ORS=" "
---
$0="2"
NR="2"
NR%3="2"
before) ORS=" "
after) ORS=" "
---
$0="3"
NR="3"
NR%3="0"
before) ORS=" "
after) ORS="
"
---
$0="4"
NR="4"
NR%3="1"
before) ORS="
"
after) ORS=" "
---
$0="5"
NR="5"
NR%3="2"
before) ORS=" "
after) ORS=" "
---
$0="6"
NR="6"
NR%3="0"
before) ORS=" "
after) ORS="
"
Run Code Online (Sandbox Code Playgroud)
请注意,NR输出记录分隔符(ORS)在哪个输入行号()上变成了换行符(如RS)而不是空白字符(如FS)。
编写相同代码的更详细的方法是:
$ cat tst.awk
{
if (NR%3 == 0) {
ORS = "\n"
}
else {
ORS = " "
}
print
}
$ awk -f tst.awk file
1 2 3
4 5 6
Run Code Online (Sandbox Code Playgroud)
仅供参考,编写在您的问题中尝试过的简洁,惯用代码的正确方法(更强大,更清晰)是:
awk '{ORS=(NR%3?FS:RS)}1'
Run Code Online (Sandbox Code Playgroud)
在某些情况下,某些情况下需要三元括号,并且总是提高可读性,因此始终使用它们。原始代码依赖于对ORS的赋值结果,该结果会产生一个非空/非零值,以便使其成为真实条件,并因此调用打印当前记录的awks默认动作。仅在需要时才在该上下文中使用操作的结果,否则有一天您的数据可能与您的预期不符时会咬住您。我没有将分配留在条件块中,而是将其移到动作块中,然后在其后添加了一个恒定的true条件,1以确保无论分配结果如何,都将打印每条记录。