如果我有一些输入,是在运行操作之前过滤数据更好awk
还是应该在 中进行所有过滤awk
?
例如,给出以下输入:
$ echo "foo\nbar\nbaz"
foo
bar
baz
我应该运行:
$ echo "foo\nbar\nbaz" | sed 1q | awk '{ print $0 " cats" }'
foo cats
或者:
$ echo "foo\nbar\nbaz" | awk 'NR == 1 { print $0 " cats" }'
foo cats
- 我为什么要运行其中任何一个?
- 我应该使用不同的工具吗?
- 我应该考虑哪些因素?
- 我如何测试这些因素?
答案1
在这种特定情况下,第二种选择是更好的选择。
一般来说,尽量减少管道中公用设施的数量会更有效。最好不要分叉(启动)不必要的进程(如第一个示例中的不必要sed
进程)。在互联网上,不难找到投诉的例子猫的无用用途。
对于大多数现代类 Unix 系统*,分叉的执行非常有效,但这取决于正在启动的进程的大小,例如,启动perl
orpython
会比sed
or慢得多awk
。
对于一次性命令,这并不重要 - 但如果您的管道位于循环内并多次运行,从管道中删除不必要的进程可以显着加快总执行时间。
具体问题
我为什么要运行其中任何一个?
如果您比另一种更熟悉其中一种的语法,那么使用您最熟悉的工具/语言可能会更好地提高代码的可读性(和可维护性)。
我应该使用不同的工具吗?
在这种具体情况下,我不这么认为。和awk
都是sed
适合此类工作的工具。
我应该考虑哪些因素?
如果您必须处理多个文件(例如,在循环中),那么速度/效率将很重要。
如果您只是经常处理一个大文件,那么代码的可读性可能更重要。
我如何测试这些因素?
您可以使用该time
实用程序来分析不同的版本,该实用程序可作为 Bash 内置的 shell 使用,也可作为独立的可执行程序使用。例如,运行两个示例命令显示第一个示例比第二个示例花费了 0.012 秒的时间。
$ time echo "foo\nbar\nbaz" | sed 1q | awk '{ print $0 " cats" }'
foo\nbar\nbaz cats
real 0m0.056s
user 0m0.000s
sys 0m0.045s
$ time echo "foo\nbar\nbaz" | awk 'NR == 1 { print $0 " cats" }'
foo\nbar\nbaz cats
real 0m0.044s
user 0m0.000s
sys 0m0.031s
请注意,分析基准受到系统负载和其他限制因素的影响,因此您需要多次重复此操作才能真实了解哪个版本比另一个版本更快。
*对于 MS Windows,分叉是成本更高,因此在 Cygwin 等环境中运行时,最小化启动的进程数量确实会产生影响。
答案2
用起来就够了awk(或者sed)用于此类简单情况的工具。多个工具的组合会过于复杂并且通常是多余的:
echo -e "foo\nbar\nbaz" | awk 'NR==1{print $0" cats"}'
输出:
foo cats
我应该考虑哪些因素?
确保所需的文本处理需要组合几种不同的工具,否则 - 使用一种不同工具的功能
假设我只需要在输入字符串中的第一个单词之前添加某个单词 - 这也很容易sed工具:
echo -e "foo\nbar\nbaz" | sed 's/^.*$/& cats/; 1q'
foo cats
echo -e
,e
标志“启用反斜杠转义的解释”
无论如何,这取决于您的输入文本有多复杂以及您的文本处理规则有多复杂