使用 awk 使用 sha1sum 进行散列
hash using sha1sum using awk
我有一个包含大约 20 列的 "pipe-separated" 文件。我只想使用 sha1sum 和 return 散列第一列,它是一个数字,如帐号,其余列按原样。
使用 awk 或 sed 执行此操作的最佳方法是什么?
Accountid|Time|Category|.....
8238438|20140101021301|sub1|...
3432323|20140101041903|sub2|...
9342342|20140101050303|sub1|...
以上是仅显示 3 列的文本文件示例。只有第一列实现了哈希函数。结果应该是:
Accountid|Time|Category|.....
104a1f34b26ae47a67273fe06456be1fe97f75ba|20140101021301|sub1|...
c84270c403adcd8aba9484807a9f1c2164d7f57b|20140101041903|sub2|...
4fa518d8b005e4f9a085d48a4b5f2c558c8402eb|20140101050303|sub1|...
什么是 Best Way™ 有待商榷。使用 awk 的一种方法是
awk -F'|' 'BEGIN { OFS=FS } NR == 1 { print } NR != 1 { gsub(/'\''/, "'\'\\\'\''", ); command = ("echo '\''" "'\'' | sha1sum -b | cut -d\ -f 1"); command | getline hash; close(command); = hash; print }' filename
也就是
BEGIN {
OFS = FS # set output field separator to field separator; we will use
# it because we meddle with the fields.
}
NR == 1 { # first line: just print headers.
print
}
NR != 1 { # from there on do the hash/replace
# this constructs a shell command (and runs it) that echoes the field
# (singly-quoted to prevent surprises) through sha1sum -b, cuts out the hash
# and gets it back into awk with getline (into the variable hash)
# the gsub bit is to prevent the shell from barfing if there's an apostrophe
# in one of the fields.
gsub(/'/, "'\''", );
command = ("echo '" "' | sha1sum -b | cut -d\ -f 1")
command | getline hash
close(command)
# then replace the field and print the result.
= hash
print
}
您会注意到顶部的 shell 命令与底部的 awk 代码之间的区别;这都是由于 shell 扩展。因为我在 shell 命令中将 awk 代码放在单引号中(双引号在那种情况下没有争议, </code> 和所有),并且因为代码包含单引号,所以它内联工作会导致反斜杠的噩梦。因此,我的建议是将 awk 代码放入一个文件中,例如 <code>foo.awk
和 运行
awk -F'|' -f foo.awk filename
相反。
这是一个 awk 可执行脚本,可以执行您想要的操作:
#!/usr/bin/awk -f
BEGIN { FS=OFS="|" }
FNR != 1 { = encodeData( ) }
47
function encodeData( fld ) {
cmd = sprintf( "echo %s | sha1sum", fld )
cmd | getline output
close( cmd )
split( output, arr, " " )
return arr[1]
}
这里是流程细分:
- 将输入和输出字段分隔符设置为
|
- 当该行不是第一 (header) 行时,re-assign
</code> 到编码值 </li>
<li>当 <code>47
为真时打印整行(总是)
这里是 encodeData
函数分解:
- 创建一个
cmd
以将数据提供给 sha1sum
- 喂给
getline
- 关闭
cmd
- 在我的系统上,在
sha1sum
之后有额外的信息,所以我通过 split
输出 来丢弃它
- Return
sha1sum
输出的第一个字段。
根据您的数据,我得到以下信息:
Accountid|Time|Category|.....
104a1f34b26ae47a67273fe06456be1fe97f75ba|20140101021301|sub1|...
c84270c403adcd8aba9484807a9f1c2164d7f57b|20140101041903|sub2|...
4fa518d8b005e4f9a085d48a4b5f2c558c8402eb|20140101050303|sub1|...
运行 通过调用 awk.script data
(或者 ./awk.script data
如果你 bash)
EdMorton 编辑:
抱歉进行了编辑,但是您上面的脚本是正确的方法,但需要进行一些调整以使其更健壮,这比尝试在评论中描述它们要容易得多:
$ cat tst.awk
BEGIN { FS=OFS="|" }
NR==1 { for (i=1; i<=NF; i++) f[$i] = i; next }
{ $(f["Accountid"]) = encodeData($(f["Accountid"])); print }
function encodeData( fld, cmd, output ) {
cmd = "echo 7" fld "7 | sha1sum"
if ( (cmd | getline output) > 0 ) {
sub(/ .*/,"",output)
}
else {
print "failed to hash " fld | "cat>&2"
output = fld
}
close( cmd )
return output
}
$ awk -f tst.awk file
104a1f34b26ae47a67273fe06456be1fe97f75ba|20140101021301|sub1|...
c84270c403adcd8aba9484807a9f1c2164d7f57b|20140101041903|sub2|...
4fa518d8b005e4f9a085d48a4b5f2c558c8402eb|20140101050303|sub1|...
f[]
数组将您的脚本与 hard-coding 需要散列的字段数分离,函数的附加参数使它们成为本地的,因此总是 null/zero每次调用时,getline 上的 if
意味着如果失败,您将不会 return 之前的成功值(参见 http://awk.info/?tip/getline),其余的可能更多 style/preference性能改进。
我有一个包含大约 20 列的 "pipe-separated" 文件。我只想使用 sha1sum 和 return 散列第一列,它是一个数字,如帐号,其余列按原样。
使用 awk 或 sed 执行此操作的最佳方法是什么?
Accountid|Time|Category|.....
8238438|20140101021301|sub1|...
3432323|20140101041903|sub2|...
9342342|20140101050303|sub1|...
以上是仅显示 3 列的文本文件示例。只有第一列实现了哈希函数。结果应该是:
Accountid|Time|Category|.....
104a1f34b26ae47a67273fe06456be1fe97f75ba|20140101021301|sub1|...
c84270c403adcd8aba9484807a9f1c2164d7f57b|20140101041903|sub2|...
4fa518d8b005e4f9a085d48a4b5f2c558c8402eb|20140101050303|sub1|...
什么是 Best Way™ 有待商榷。使用 awk 的一种方法是
awk -F'|' 'BEGIN { OFS=FS } NR == 1 { print } NR != 1 { gsub(/'\''/, "'\'\\\'\''", ); command = ("echo '\''" "'\'' | sha1sum -b | cut -d\ -f 1"); command | getline hash; close(command); = hash; print }' filename
也就是
BEGIN {
OFS = FS # set output field separator to field separator; we will use
# it because we meddle with the fields.
}
NR == 1 { # first line: just print headers.
print
}
NR != 1 { # from there on do the hash/replace
# this constructs a shell command (and runs it) that echoes the field
# (singly-quoted to prevent surprises) through sha1sum -b, cuts out the hash
# and gets it back into awk with getline (into the variable hash)
# the gsub bit is to prevent the shell from barfing if there's an apostrophe
# in one of the fields.
gsub(/'/, "'\''", );
command = ("echo '" "' | sha1sum -b | cut -d\ -f 1")
command | getline hash
close(command)
# then replace the field and print the result.
= hash
print
}
您会注意到顶部的 shell 命令与底部的 awk 代码之间的区别;这都是由于 shell 扩展。因为我在 shell 命令中将 awk 代码放在单引号中(双引号在那种情况下没有争议, </code> 和所有),并且因为代码包含单引号,所以它内联工作会导致反斜杠的噩梦。因此,我的建议是将 awk 代码放入一个文件中,例如 <code>foo.awk
和 运行
awk -F'|' -f foo.awk filename
相反。
这是一个 awk 可执行脚本,可以执行您想要的操作:
#!/usr/bin/awk -f
BEGIN { FS=OFS="|" }
FNR != 1 { = encodeData( ) }
47
function encodeData( fld ) {
cmd = sprintf( "echo %s | sha1sum", fld )
cmd | getline output
close( cmd )
split( output, arr, " " )
return arr[1]
}
这里是流程细分:
- 将输入和输出字段分隔符设置为
|
- 当该行不是第一 (header) 行时,re-assign
</code> 到编码值 </li> <li>当 <code>47
为真时打印整行(总是)
这里是 encodeData
函数分解:
- 创建一个
cmd
以将数据提供给sha1sum
- 喂给
getline
- 关闭
cmd
- 在我的系统上,在
sha1sum
之后有额外的信息,所以我通过split
输出 来丢弃它
- Return
sha1sum
输出的第一个字段。
根据您的数据,我得到以下信息:
Accountid|Time|Category|.....
104a1f34b26ae47a67273fe06456be1fe97f75ba|20140101021301|sub1|...
c84270c403adcd8aba9484807a9f1c2164d7f57b|20140101041903|sub2|...
4fa518d8b005e4f9a085d48a4b5f2c558c8402eb|20140101050303|sub1|...
运行 通过调用 awk.script data
(或者 ./awk.script data
如果你 bash)
EdMorton 编辑: 抱歉进行了编辑,但是您上面的脚本是正确的方法,但需要进行一些调整以使其更健壮,这比尝试在评论中描述它们要容易得多:
$ cat tst.awk
BEGIN { FS=OFS="|" }
NR==1 { for (i=1; i<=NF; i++) f[$i] = i; next }
{ $(f["Accountid"]) = encodeData($(f["Accountid"])); print }
function encodeData( fld, cmd, output ) {
cmd = "echo 7" fld "7 | sha1sum"
if ( (cmd | getline output) > 0 ) {
sub(/ .*/,"",output)
}
else {
print "failed to hash " fld | "cat>&2"
output = fld
}
close( cmd )
return output
}
$ awk -f tst.awk file
104a1f34b26ae47a67273fe06456be1fe97f75ba|20140101021301|sub1|...
c84270c403adcd8aba9484807a9f1c2164d7f57b|20140101041903|sub2|...
4fa518d8b005e4f9a085d48a4b5f2c558c8402eb|20140101050303|sub1|...
f[]
数组将您的脚本与 hard-coding 需要散列的字段数分离,函数的附加参数使它们成为本地的,因此总是 null/zero每次调用时,getline 上的 if
意味着如果失败,您将不会 return 之前的成功值(参见 http://awk.info/?tip/getline),其余的可能更多 style/preference性能改进。