【问题标题】:Is it possible to use awk to print all line in a file and then do a command on a single column?是否可以使用 awk 打印文件中的所有行,然后在单个列上执行命令?
【发布时间】:2013-08-21 22:40:59
【问题描述】:

我想知道是否可以使用 AWK 打印文件中的所有行,然后选择文件中的这些列之一以使用此命令散列该值:

openssl dgst -sha1 | sed 's/^.* //'

我目前正在使用读取命令,但它似乎写得很慢。这是我目前拥有的:

while IFS="," read -ra line;
do
    if [ "${line[1]}" != "" ]; then
        echo -n "${line[*]}, Hash Value:"; echo "${line[1]}" | openssl dgst -sha1 | sed 's/^.* //'
    else
        if [ "${line[1]}" == "" ]; then
            echo "${line[*]}, Hash Value: None";
        fi
    fi
done

所以我想我最终要说的是,我怎样才能使用 AWK 来打印所有行并在特定列上执行命令?希望加快阅读过程。另外,是否可以使用 AWK 打印目录中所有文件的列?

谢谢大家!

更新

下面是包含将所有文本文件转换为 DOS 到 UNIX 格式的代码。下面是 unix.txt 的一些输出。最后,下面是我的脚本。

dos2unix

$ dos2unix *.txt
dos2unix: converting file unix.txt to Unix format ...
dos2unix: converting file woohoo.txt to Unix format ...

unix.txt 输入

7051,95230163,-1,53200703
7051,95230163,-1,53200703
7051,95230163,-1,53200703
53200703,2286,Mon Jul 01 13:30:03 PDT 2013
53200703,2286,Mon Jul 01 13:30:03 PDT 2013
53200703,2286,Mon Jul 01 13:30:03 PDT 2013

unix.txt 输出

$ ./trial.sh < unix.txt
7051,95230163,-1,53200703, Hash Value: c9b674deec9973f4d0feb83433d6db0b4ea5012a
7051,95230163,-1,53200703, Hash Value:
7051,95230163,-1,53200703, Hash Value:
53200703,2286,Mon Jul 01 13:30:03 PDT 2013, Hash Value: 2a8db89cc6f4ccdc0ce423011e869cb8b29b1003
53200703,2286,Mon Jul 01 13:30:03 PDT 2013, Hash Value:
53200703,2286,Mon Jul 01 13:30:03 PDT 2013, Hash Value:

脚本

gawk -F',' '
function hash(val, var) 
    {
    if (val == "") { 
           var = "None" 
          }
              else {
                    "echo \"" val "\" | openssl dgst -sha1" | getline var
                   sub(/.* /,"",var) 
                    }
              return var 
                    }
{ printf "%s, Hash Value: %s\n", $0, hash($2) } '

正如您在针对 unix.txt 运行脚本时所看到的,包含第二列的值不是散列值。前几行虽然是散列。不确定发生了什么,但它应该可以工作。

【问题讨论】:

  • “极慢”有多慢?
  • @Vaughn 好吧,我有多个文件需要处理,一个文件是 255MB。那个文件在我的机器上可能需要 3-4 个小时。我希望最终只需要 15 到 20 分钟即可完成该大小的文件。

标签: bash shell unix awk


【解决方案1】:
$ cat input.txt         
7051,95230163,-1,53200703
7051,95230163,-1,53200703
7051,95230163,-1,53200703
53200703,2286,Mon Jul 01 13:30:03 PDT 2013
53200703,2286,Mon Jul 01 13:30:03 PDT 2013
53200703,2286,Mon Jul 01 13:30:03 PDT 2013
$                       
$ cat trial.sh
gawk -F',' '
function hash(val, var) {
    if (val == "") { 
        var = "None" 
    }
    else {
        cmd = "echo \"" val "\" | openssl dgst -sha1"
        cmd | getline var
        close(cmd)
        sub(/.* /,"",var) 
    }
    return var 
}
{ printf "%s, Hash Value: %s\n", $0, hash($2) }
'
$ 
$ ./trial.sh < input.txt
7051,95230163,-1,53200703, Hash Value: c9b674deec9973f4d0feb83433d6db0b4ea5012a
7051,95230163,-1,53200703, Hash Value: c9b674deec9973f4d0feb83433d6db0b4ea5012a
7051,95230163,-1,53200703, Hash Value: c9b674deec9973f4d0feb83433d6db0b4ea5012a
53200703,2286,Mon Jul 01 13:30:03 PDT 2013, Hash Value: 2a8db89cc6f4ccdc0ce423011e869cb8b29b1003
53200703,2286,Mon Jul 01 13:30:03 PDT 2013, Hash Value: 2a8db89cc6f4ccdc0ce423011e869cb8b29b1003
53200703,2286,Mon Jul 01 13:30:03 PDT 2013, Hash Value: 2a8db89cc6f4ccdc0ce423011e869cb8b29b1003

请注意,上面是 GNU-awk 特定的,因为它使用协进程将 shell 命令的输出通过管道传输到 getline 读取。

另外,既然我看到您的示例输入包含许多重复项,通过仅在第一次计算哈希值并在之后使用它来避免重复键字段的外部命令和管道,这可能会更有效:

$ cat trial.sh               
gawk -F',' '
function hash(val) {
    if ( !(val in map) ) {
        if (val == "") { 
            map[val] = "None" 
        }
        else {
            cmd = "echo \"" val "\" | openssl dgst -sha1"
            cmd | getline map[val]
            close(cmd)
            sub(/.* /,"",map[val])
        }
    }
    return map[val]
}
{ printf "%s, Hash Value: %s\n", $0, hash($2) }
'

是的,当然,您可以使用 awk 从目录中的所有文件中打印您想要的任何内容:

awk '{ print <whatever> }' /dir/*

【讨论】:

  • 这似乎是迄今为止我一直希望快速完成的最接近的事情。唯一的问题是它没有在第一行之后的“哈希值:”部分之后打印值。去看看我能不能找出原因。
  • 如果您复制/粘贴您的命令并将其输出到您提出的原始问题中,我们可以告诉您问题所在。同时运行gawk --version
  • 我刚刚注意到您说“...在第一行之后”,这告诉我您的输入文件有问题,因为 awk 脚本在各行之间的行为不会有所不同。可能您的输入文件是在 Windows 上创建的,因此每行末尾都有虚假的 control-M。对它运行cat -v 进行检查并运行dos2unix 进行修复。
  • 美丽,就像魅力一样。非常感谢帮忙。当我有足够的代表时,我会确保 +1。再次感谢您的帮助。
  • 更新速度比原来还快。非常感谢!
【解决方案2】:

可以从awk 运行shell 命令。您只需要正确引用,如下所示:

echo "123" | awk '{ print $0 | "openssl dgst -sha1 | sed '"'s/^.* //'"'" }'

输出:

a8fdc205a9f19cc1c7507a60c4f01b13d11d7fd0

【讨论】:

  • 感谢您的帮助,但我使用了另一个示例来说明我需要做的事情。
【解决方案3】:

通常,您会执行以下操作:

cat file
awk '{print $2}' file | openssl dgst -sha1 | sed 's/^.* //'

这使用cat 将文件中的所有行复制到标准输出,然后使用awk 打印第2 列中的值,该值通过管道传送到opensslsed。你有什么理由不能这样做吗?

如果输入来自命令(因此您无法重读),则您必须更加努力,但您明确地说“来自文件”,所以我认为这不是问题。

【讨论】:

  • 感谢您的意见,不过使用了另一个示例。
  • 如果你想要每一行的哈希值,那么我给出的不是你需要的——但我给出的是对“使用 AWK 打印文件中的所有行然后选择文件中的这些列之一来散列该值”。我想“那个价值”与“那些价值”可能是我错过的线索。
猜你喜欢
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 2018-01-16
  • 2015-01-06
  • 1970-01-01
  • 2014-06-07
  • 2014-09-16
  • 1970-01-01
相关资源
最近更新 更多