我有一个充满 md5 校验和和文件名的文件。我需要对每一行执行一些处理,所以我需要知道:
- 哪个是校验和
- 文件名是哪个
并采取相应行动。也就是说,我需要将校验和放入变量中,然后是文件名。文件名中可能包含非 ASCII 字符,但我不希望看到换行符。它看起来像这样:
05c00367e8914ca1be0964821d127977 ./.fseventsd/0000000000097aa1
cd9d4291f59a43c0e3d73ff60a337bb5 ./.fseventsd/00000000000fdfec
5d1280769e741e04622cfd852f33a138 ./.fseventsd/0000000000103197
8dda3534e5bbc0be1d15db2809123c50 ./.fseventsd/000000000017c9ca
(...etc., about 100,000 lines)
传统上,我可能会执行这样的操作:
md5sum=$(echo $line | awk '{print $1}')
filename=$(echo $line | sed 's/[^ ]* //')
但如果我这样做的话会快多少:
md5sum=${line%%" "*}
filename=${line#*" "}
答案1
是的,使用 bash 内部命令可以避免许多系统调用。尤其是有递归的时候。
另一个例子:我们必须使用 * 来对抗 $(ls)。
Bash 提供了一些对字符串进行简单操作的方法(剪切和替换)。但仅此而已。因为它不是为此而设计的。示例:在没有外部命令的情况下很难验证字符串中模式的存在。
外部程序针对其任务进行了更优化(cat、sed、grep、awk、cut、sort...)
答案2
我通过设置其中一个变量进行测试。执行此脚本两次:
while read line; do
md5sum=${line%%" "*}
#md5sum=$(echo $line | awk '{print $1}')
echo "SUM: $md5sum FILE:_$file"
done < manifest.Stuph.180620
首先与
md5sum=${line%%" "*}
接下来是
md5sum=$(echo $line | awk '{print $1}')
其中文件“manifest.Stuph.180620”的长度为 100939 行(== 约 14MiB),结果如下:
第一次运行(使用 bash 的内置字符串操作)
real 0m4.750s
user 0m4.174s
sys 0m0.550s
第二次运行(使用管道)
real 10m54.255s
user 4m42.257s
sys 7m32.880s
有些人(例如我自己)会说,如果速度很重要,那么您无论如何都不应该在 shell 中乱搞,但有时您可能希望提高效率 - 无论您使用什么环境来完成工作。
请注意,这样做:
while read md5sum filename; do
(...etc...)
甚至比进行变量赋值更有效,但还没有达到消除命令替换/管道/awk 构造的程度。我发现最有趣的是 bash 内置性能和使用外部命令之间的差异。我会更加勤奋地学习和使用精美的内置东西!