您可以考虑使用包含 md5 支持的语言,或者至少缓存 md5 结果(我假设城市和年龄的域是有限的,小于行数)。
Perl 开箱即用地支持 md5:
perl -M'Digest::MD5 qw(md5_hex)' -F'\|' -le 'if (2..eof) {
$F[$_] = md5_hex($F[$_]) for (1,3);
print join "|",@F
} else { print }'
在线演示:https://ideone.com/xg6cxZ(令我惊讶的是 ideone 在 bash 中提供了 perl)
-
Digest::MD5 是一个核心模块,任何 perl 安装都应该有它
-
-M'Digest::MD5 qw(md5_hex)' - 这会加载 md5_hex 函数
-
-l 处理行尾
-
-F'\|' - 自动拆分字段 | (这意味着 -a 和 -n)
-
2..eof - 范围运算符(或某些人想称之为触发器)- 在第 2 行和文件末尾之间为真
-
$F[$_] = md5_hex($F[$_]) - 将字段 $_ 替换为 md5 总和
-
for (1,3) - statement modifier 运行 1 和 3 的语句,将 $_ 别名给它们
-
print join "|",@F - 打印修改后的字段
-
else { print } - 处理标题
关于速度的注意事项:在我的机器上,它在大约 100 毫秒内处理约 100,000 行,而 answer 的 awk 变体在约 1 分 14 秒内处理 5000 行(我是'没有足够的耐心等待 100,000 行)
time perl -M'Digest::MD5 qw(md5_hex)' -F'\|' -le 'if (2..eof) { $F[$_] = md5_hex($F[$_]) for (1,3);print join "|",@F } else { print }' <sample2.txt > out4.txt
real 0m0.121s
user 0m0.118s
sys 0m0.003s
$ time awk -F'|' -v OFS='|' -i md5.awk '{ print $1,md5($2),$3,md5($4) }' <(head -5000 sample2.txt) >out2.txt
real 1m14.205s
user 0m50.405s
sys 0m35.340s
md5.awk 是这样定义 md5 函数的:
$ cat md5.awk
function md5(str, cmd, l, hex) {
cmd= "/bin/echo -n "str" | openssl md5 -r"
if ( ( cmd | getline l) > 0 )
hex = substr(l,0,32)
close(cmd)
return hex
}
- 我正在使用
/bin/echo,因为有一些 shell 变体,其中 echo 没有 -n
- 我使用
-n 主要是因为我希望能够将结果与 perl 结果进行比较
-
substr(l,0,32) - 在我的机器上 openssl md5 不只返回总和,它还有文件名 - 请参阅:https://ideone.com/KGMWPe - substr 只获取相关部分
- 我使用了一个单独的文件,因为它看起来更简洁,而且我可以相当容易地在函数实现之间切换
正如我一开始所说,如果你真的想使用awk,至少缓存openssl工具的结果。
$ cat md5memo.awk
function md5(str, cmd, l, hex) {
if (cache[str])
return cache[str]
cmd= "/bin/echo -n "str" | openssl md5 -r"
if ( ( cmd | getline l) > 0 )
hex = substr(l,0,32)
close(cmd)
cache[str] = hex
return hex
}
通过上述缓存,结果显着提高:
$ time awk -F'|' -v OFS='|' -i md5memo.awk '{ print $1,md5($2),$3,md5($4) }' <(head -5000 sample2.txt) >outmemo.txt
real 0m0.192s
user 0m0.141s
sys 0m0.085s
[savuso@localhost hash]$ time awk -F'|' -v OFS='|' -i md5memo.awk '{ print $1,md5($2),$3,md5($4) }' <sample2.txt >outmemof.txt
real 0m0.281s
user 0m0.222s
sys 0m0.088s
但是你的里程数不同:sample2.txt 有 100000 行,2 美元有 5 个不同的值,4 美元有 40 个不同的值。现实生活中的数据可能会有所不同!
注意:我刚刚意识到我的 awk 实现不处理标头,但您可以从其他答案中得到这一点