【问题标题】:Add an md5 hash value to a big CSV file将 md5 哈希值添加到大 CSV 文件
【发布时间】:2016-02-12 21:41:09
【问题描述】:

我需要为 80 GB csv 文件的每一行插入一个包含第一个字段的 MD5 哈希值的新字段。

对于小型项目,我可以通过将字段值传递给 excel 来完成此操作

=WEBSERVICE(CONCATENATE("https://helloacm.com/api/md5/?s="&ENCODEURL(A1)))

但是,对于 80 GB 的文件,这不是一个选项。

是否可以通过 AWK 提取这个海量 csv 中每一行的第一个字段,计算第一个字段内容的 md5,然后将该值插入到同一行中?

示例行:

原文:

"value001","value002","Value003","Value004","Value005","Value006","Value007"

修改了插入 md5ofvalue001 字段的示例行:

"value001","MD5ofValue001","value002","Value003","Value004","Value005","Value006","Value007"

【问题讨论】:

  • @shawnt00 是的,这是一个重复的问题,但是在该问题中选择的答案是错误的,所以如果将其关闭为该问题的副本将会很有用。
  • @shawnt100 - 此外,那里选择的答案使用 awk,对于具有大量行数的文件,这种类型的任务非常慢。

标签: csv hash awk sed


【解决方案1】:

awk 来救援!

这是给你的概念证明

$ awk -F, -v OFS=, -v q='\"' '{
         cmd= "echo " $1 " | md5sum | cut -f1 -d\" \""; 
         (cmd | getline md5); print $1, q md5 q}' file

"value001","c36a5b774bfb2fd236331ac5ebef4266"

【讨论】:

  • 这个解决方案看起来可以达到预期的结果,但是,它产生了您给出的示例,并且不包含每行的 CSV 中的其他字段。使用 awk 我将如何包含它们?例如使用您的示例: "value001","c36a5b774bfb2fd236331ac5ebef4266","value002","Value003","Value004","Value005","Value006","Value007"
  • 嗯,这就是我称之为概念证明的原因。如果你坚持$1=$1 OFS q md5 q; print 应该这样做。
【解决方案2】:

awk 很好,但是对于您的问题,如果您必须使用 system() 来计算 md5,它可能会太慢。如果第一个字段有任何嵌入的逗号,awk 也可能不适合该任务。

无论如何,这里有一个使用php 的快速(或至少快得多)解决方案,我发现它对各种条纹和色调的CSV 有很好的支持。您应该能够在 Mac 或类似 Linux 的平台上将其作为脚本运行。

#!/usr/bin/env php
<?php

# Syntax: $0 [PATHNAME]
# A filter that expects its input to have the CSV format.
# Input is taken from STDIN if PATHNAME is - or not specified.
# Output is the same CSV but with the md5 of the first field tacked on.

$file = ($argc > 1 && $argv[1] != "" ) ? $argv[1] : 'php://stdin';
if ( $file == "-" ) { $file = 'php://stdin'; }

$handle = @fopen($file, "r");
$sep = ",";

if ($handle) {
  while (($data = fgetcsv($handle, 0, $sep)) !== FALSE) {
    $num = count($data);
    $data[] = md5($data[0]);
    fputcsv(STDOUT, $data, $sep);
  }
  fclose($handle);
} else {
  echo "{$argv[0]}: unable to fopen $argv[1]\n";
  exit(1);
}
?>

如果您想保持输入行不变,那么您可以逐字阅读该行并使用 str_getcsv() 对其进行解析,等等。

【讨论】:

  • 我用 PHP 做的很少,但是我试了一下,它给了我无法打开文件的错误。
  • @trackthis - 抱歉 - cmets 放错地方了。固定。
  • Peak,这正是我希望得到的计算结果。但是,仍然存在两个问题:1. 我在此脚本输出中的 20 个左右字段中的大多数,包括第一个字段和新的 md5 字段都没有它们的 " 文本限定符。2. 在这个脚本中,我可以通过管道传输到另一个 csv vs 直接打印到终端窗口?
  • (1) 如果不包含引号,则 CSV 不需要引号。如果您想复制输入,我建议计算感兴趣列的 md5 总和,然后使用这些 md5 总和粘贴原始文件(例如,使用 paste 命令)。或者您可以编写自己的 fputcsv() :-) (2) 要将输出重定向到文件,最简单的方法是使用“>”(例如 SCRIPTNAME inpathname > outpathname)。
  • 虽然我的问题的这个解决方案不是使用 AWK。考虑到我正在处理的文件的大小,我确实找到了正确的解决方案。
【解决方案3】:

由于您询问如何在 awk 中执行此操作,并假设 echo val | md5sum 是如何计算“md5sum”,这是执行此操作的 awk 脚本:

$ cat tst.awk
BEGIN { FS=OFS="," }
{
    cmd = "echo " $1 " | md5sum"
    if ( (cmd | getline md5) > 0 ) {
        sub(/ .*/,"",md5)
    }
    else {
        printf "Warning: Failed to calculate md5sum of %s at input line %d\n", $1, NR | "cat>&2"
        md5 = "N/A"
    }
    close(cmd)
    $1 = $1 OFS "\"" md5 "\""
    print
}

$ awk -f tst.awk file
"value001","c36a5b774bfb2fd236331ac5ebef4266","value002","Value003","Value004","Value005","Value006","Value007"

如其他地方所述,由于您在每一行都跳入和跳出 shell,因此与可以在内部进行 md5sum 计算的工具相比,这会很慢。

【讨论】:

    猜你喜欢
    • 2016-03-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-03
    • 2015-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多