关于使用ORS,NR,FS,RS的awk命令的说明

use*_*ser 3 linux awk

我有一个样本数据集:

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 -不确定如何适合命令。

谢谢。

Ed *_*ton 5

%是模运算符(请参阅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以确保无论分配结果如何,都将打印每条记录。