首页 > 解决方案 > 为什么使用 cut 比 awk 从文件中的每一行截取两个字符串要慢得多?

问题描述

我有一个大约 160 万行的文件,每行大约

2018_08_01_02_00_00_OL13F1i5014j2513,0
2018_08_01_02_00_00_OL13F1i5055j2490,0

文件名为 order_all.csv。

现在我有两个脚本

外壳一

#!/bin/bash
while read line
do
    st="set "
    key="$(echo $line | cut -d',' -f1)"
    value="$(echo $line | cut -d',' -f2)"
    echo "$st$key $value" >> output

done < order_all.csv

外壳二

cat order_all.csv | awk -F ',' '{print "set " $1,$2}' > output

但是我发现第二个脚本比第一个快得多。什么原因?另外,我也希望脚本输出的每一行的换行符都是\r\n。我能做些什么呢?

标签: shell

解决方案


正如@zerkms 所说,这里的性能差异更多地取决于算法的效率,而不是正在运行的文本处理命令。

要了解两者之间的差异,您需要了解 shell 与大多数其他语言相比的工作方式。由于 shell 基本上是一个一个地执行的单个 unix 程序,因此每一行(实际上是命令)的性能是另一种语言的整个程序的性能,其他一切都相同。

这相当于在这里,通过围绕每一行数据构建一个循环,然后执行一个命令,“cut”,你承担了为每一行数据启动一个新程序的开销(在这种情况下为 2,因为你叫 cut 2 次)。

执行任何 unix 命令的单个实例的幕后都是一些非常昂贵的操作系统调用,这些调用需要花费大量时间,例如 fork(),更不用说将命令加载到内存中的过程以及那里涉及的所有内容。

在您的第二个版本中,您巧妙地避免使用管道“|”为每一行文本启动新命令。该管道将​​数据流式传输到“awk”。在此设计中,Awk 仅启动一次,因为它一次从 STDIN 读取一行,直到遇到流中的文件结尾。'cut' 也可以以这种方式工作(在流中),但处理文本在 'cut' 中受到更多限制。因此,这里的文本处理发生在一个进程中,awk 程序加载和 fork 开销只完成了一次,而文本处理发生了 160 万次。

我希望这会有所帮助。


推荐阅读