awk -F'/' '{ print $1 |" sort " }' infile > outfile
与
awk -F'/' '{ print $1 }' infile | sort > outfile
如果我在awk
中使用管道(或重定向),这些MVCE是否完全等效,或者是否存在我不知道的可移植性/性能问题。
两个命令都会产生正确的输出。
更新:我自己做了一些研究——见下面的答案。
tl;dr在awk中使用管道的速度可能是的两倍。
我去看了一下gawk源中的io.c
只要不使用协同过程,使用awk的管道就是POSIX。即|&
如果你的操作系统不支持管道(评论中提到了这一点),gawk会像你预期的那样通过写入文件来模拟管道。这需要一段时间,但至少你有管道,而你没有。
如果你有一个真正的操作系统,它会派生子系统并在那里编写输出,所以你不会期望在awk中使用管道会带来巨大的性能下降。
有趣的是,gawk对等简单情况进行了一些优化
awk '{print $1}'
所以我运行了一个测试用例。
for i in $(seq 1 10000000); do echo $(( 10000000-$i )) " " $i;done > infile
1000万条记录似乎足以消除系统中其他工作的差异。
然后
time awk '{ print $1 }' infile | sort -n > /dev/null
real 0m10.350s
user 0m7.770s
sys 0m3.000s
或平均约为。
但
time awk '{ print $1 | " sort -n " }' infile > /dev/null
real 0m25.870s
user 0m13.880s
sys 0m13.030s
正如你所看到的,这是一个巨大的差异。
因此得出结论:
尽管它可能会慢得多,但在许多用例中,收益远远超过额外的性能打击。实际上,只有在像MVCE这样的简单情况下,你才应该把管道放在外面。
这里讨论了重定向到awk
与使用文件名调用awk
之间的区别。虽然没有直接的关系,但如果你读到这里,可能会感兴趣。
如果在awk
中使用|
,打印语句的输出将累积为一个字符串,然后使用该字符串执行"xxx"中的shell命令。
考虑:
$ echo 1 4 2 3 | awk '{for (i=1; i<=NF; i++) print $i}'
1
4
2
3
现在试试:
$ echo 1 4 2 3 | awk '{for (i=1; i<=NF; i++) print $i | "sort" }'
1
2
3
4
1n4n2n3
的单个字符串在内部构造,然后通过awk传递给sort
。这可以组合成更复杂的调用,例如:
awk '{ print $1 > "names.unsorted"
command = "sort -r > names.sorted"
print $1 | command }' names
更多关于重定向的GNU awk手册。