【发布时间】:2011-11-06 00:32:19
【问题描述】:
如何在 awk 或 sed 中用其哈希值(如 MD5)替换列?
原始文件超级大,所以我需要这个非常高效。
【问题讨论】:
如何在 awk 或 sed 中用其哈希值(如 MD5)替换列?
原始文件超级大,所以我需要这个非常高效。
【问题讨论】:
我复制粘贴的 larsks 的回复,但我添加了关闭行,以避免在此帖子中指出的问题:gawk / awk: piping date to getline *sometimes* won't work
awk '{
tmp="echo " $2 " | openssl md5 | cut -f2 -d\" \""
tmp | getline cksum
close(tmp)
$2=cksum
print
}' < sample
【讨论】:
$2 的内容不带引号地传递给shell,因此它对通配、工作拆分、恶意代码注入等开放(使用tmp="echo \047" $2 "\047... 代替)并且在a 中使用getline如果它以任何方式失败,它会悄悄地破坏你的输出,请参阅awk.freeshell.org/AllAboutGetline了解何时/如何使用getline。
所以,你真的不想用awk 来做这件事。任何流行的高级脚本语言——Perl、Python、Ruby 等——都会以一种更简单、更健壮的方式来做到这一点。话虽如此,这样的事情会起作用。
给定这样的输入:
this is a test
(例如,一行有四列),我们可以用它的 md5 校验和替换给定的列,如下所示:
awk '{
tmp="echo " $2 " | openssl md5 | cut -f2 -d\" \""
tmp | getline cksum
$2=cksum
print
}' < sample
这依赖于 GNU awk(在 Linux 系统上你可能会默认拥有它),它使用 openssl 来生成 md5 校验和。我们首先在tmp 中构建一个shell 命令行,将选定的列传递给md5 命令。然后我们将输出通过管道传输到cksum 变量中,并将第 2 列替换为校验和。鉴于上面的示例输入,这个 awk 脚本的输出将是:
this 7e1b6dbfa824d5d114e96981cededd00 a test
【讨论】:
$2) 包含 shell 元字符,它可能会做意想不到的事情。使用单引号并不能完全解决这个问题(该字段本身可能包含单引号)。并且使用echo 而不是echo -n 意味着您将获得附加换行符的字段的md5sum(7e1b... 是"is\n" 的md5sum,而不是"is"。)
perldoc perlfunc 并搜索对于“系统”)。
这可能使用 Bash/GNU sed 工作:
<<<"this is a test" sed -r 's/(\S+\s)(\S+)(.*)/echo "\1 $(md5sum <<<"\2") \3"/e;s/ - //'
this 7e1b6dbfa824d5d114e96981cededd00 a test
或主要是 sed 解决方案:
<<<"this is a test" sed -r 'h;s/^\S+\s(\S+).*/md5sum <<<"\1"/e;G;s/^(\S+).*\n(\S+)\s\S+\s(.*)/\2 \1 \3/'
this 7e1b6dbfa824d5d114e96981cededd00 a test
用 md5sum 替换 is 中的 this is a test
解释:
在第一个中:- 识别列并使用反向引用作为 Bash 命令中的参数,该命令被替换和评估,然后进行外观更改以丢失 md5sum 命令生成的文件描述(在本例中为标准输入)。
在第二个中:- 与第一个类似,但将输入字符串放入保存空间,然后在评估 md5sum 命令后,将字符串 G 附加到模式空间(md5sum 结果)并使用替换排列以适应。
【讨论】:
'/e 是什么?它是 sed 标志吗?我无法让它工作并通过 bash 提示符获取:sh: 1: Syntax error: redirection unexpected
e 标志是 GNU 特定的,它评估模式空间(在替换之后),就好像它在当前 shell 中一样。
你也可以用 perl 做到这一点:
echo "aze qsd wxc" | perl -MDigest::MD5 -ne 'print "$1 ".Digest::MD5::md5_hex($2)." $3" if /([^ ]+) ([^ ]+) ([^ ]+)/'
aze 511e33b4b0fe4bf75aa3bbac63311e5a wxc
如果您想混淆大量数据,它可能比 sed 和 awk 更快,后者需要为每行分叉一个 md5sum 进程。
【讨论】:
虽然我没有进行任何基准测试,但使用 read 可能比使用 awk 更愉快。
输入(scratch001.txt):
foo|bar|foobar|baz|bang|bazbang
baz|bang|bazbang|foo|bar|foobar
使用read转换:
while IFS="|" read -r one fish twofish red fishy bluefishy; do
twofish=`echo -n $twofish | md5sum | tr -d " -"`
echo "$one|$fish|$twofish|$red|$fishy|$bluefishy"
done < scratch001.txt
产生输出:
foo|bar|3858f62230ac3c915f300c664312c63f|baz|bang|bazbang
baz|bang|19e737ea1f14d36fc0a85fbe0c3e76f9|foo|bar|foobar
【讨论】: