【问题标题】:Awk replace a column with its hash valueawk 用它的哈希值替换一列
【发布时间】:2011-11-06 00:32:19
【问题描述】:

如何在 awk 或 sed 中用其哈希值(如 MD5)替换列?

原始文件超级大,所以我需要这个非常高效。

【问题讨论】:

    标签: shell sed awk


    【解决方案1】:

    我复制粘贴的 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
    【解决方案2】:

    所以,你真的不想用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
    

    【讨论】:

    • 这对 awk 来说确实是错误的。你的时间最好花在我提到的其他一种语言上。
    • 我发现这个解决方案有几个问题。一方面,如果列 ($2) 包含 shell 元字符,它可能会做意想不到的事情。使用单引号并不能完全解决这个问题(该字段本身可能包含单引号)。并且使用echo 而不是echo -n 意味着您将获得附加换行符的字段的md5sum(7e1b..."is\n" 的md5sum,而不是"is"。)
    • 使用 Perl,您可以使用一个模块来执行 md5 校验和,而无需调用外部程序——或者,如果您愿意,您可以调用外部程序而无需通过 shell (perldoc perlfunc 并搜索对于“系统”)。
    • ...这就是为什么我开始(并跟进)这个问题并不适合 awk。
    • 此解决方案为处理的每一行创建了无效进程。有人知道如何预防吗?
    【解决方案3】:

    这可能使用 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
    • @martin 替换命令上的 e 标志是 GNU 特定的,它评估模式空间(在替换之后),就好像它在当前 shell 中一样。
    • 谢谢,但无论如何,在您提供的第一个示例中,上述错误仍然发生在我这边。
    • 好吧,在我的主机上,出于任何原因,替换似乎在“sh”而不是“bash”中运行,因此我在命令行上从 bash 发出命令。
    【解决方案4】:

    你也可以用 perl 做到这一点:

    echo "aze qsd wxc" | perl -MDigest::MD5 -ne 'print "$1 ".Digest::MD5::md5_hex($2)." $3" if /([^ ]+) ([^ ]+) ([^ ]+)/' 
    aze 511e33b4b0fe4bf75aa3bbac63311e5a wxc
    

    如果您想混淆大量数据,它可能比 sed 和 awk 更快,后者需要为每行分叉一个 md5sum 进程。

    【讨论】:

      【解决方案5】:

      虽然我没有进行任何基准测试,但使用 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
      

      【讨论】:

        猜你喜欢
        • 2013-07-21
        • 1970-01-01
        • 2015-09-03
        • 2016-07-19
        • 1970-01-01
        • 1970-01-01
        • 2016-07-20
        • 2011-12-14
        • 1970-01-01
        相关资源
        最近更新 更多