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

我有一个样本数据集:

1
2
3
4
5
6

它被下面的awk命令成功地解析为所需的输出
awk 'ORS=NR%3?FS:RS'

   1 2 3
   4 5 6

你能解释一下这个命令的作用吗?我无法把各个部分拼凑起来。
据我所知:
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
}

是的。
$ 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="
"

请注意,在哪个输入行号(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

请注意,正确的(更加健壮和清晰的)编写问题中尝试的简洁、惯用的代码的方法是:
awk '{ORS=(NR%3?FS:RS)}1'

在某些情况下,在某些awk中需要三元组周围的paren,并且总是提高可读性,所以总是使用它们。原始代码依赖于ORS赋值的结果,生成一个非空/非零值,以便它是一个真实的条件,因此调用awks打印当前记录的默认操作。只有在你需要的时候才使用这个上下文中的一个操作的结果,否则有一天当你的数据不完全符合你的预期时,它会咬你一口。我没有将赋值放在条件块中,而是将它移到操作块中,然后添加一个常量true条件1,以确保打印每个记录,而不管赋值结果如何。

公众号