我有一个"管道分离"文件大约有20列。我想使用sha1sum散列第一列是一个类似帐号的数字,并按原样返回其余列。
使用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|...
答案 0 :(得分:3)
最佳方式™的目的是辩论。使用awk的一种方法是
awk -F'|' 'BEGIN { OFS=FS } NR == 1 { print } NR != 1 { gsub(/'\''/, "'\'\\\\\'\''", $1); command = ("echo '\''" $1 "'\'' | sha1sum -b | cut -d\\ -f 1"); command | getline hash; close(command); $1 = 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(/'/, "'\\''", $1);
command = ("echo '" $1 "' | sha1sum -b | cut -d\\ -f 1")
command | getline hash
close(command)
# then replace the field and print the result.
$1 = hash
print
}
您会注意到顶部的shell命令和底部的awk代码之间的差异;这完全归功于shell扩展。因为我将awk代码放在shell命令中的单引号中(双引号在该上下文中不起作用,使用$1
和所有内容进行辩论),并且因为代码包含单引号,所以它使内联工作导致反睫毛的噩梦。因此,我的建议是将awk代码放入一个文件中,比如foo.awk
,然后运行
awk -F'|' -f foo.awk filename
代替。
答案 1 :(得分:2)
这是一个awk可执行脚本,可以执行您想要的操作:
#!/usr/bin/awk -f
BEGIN { FS=OFS="|" }
FNR != 1 { $1 = encodeData( $1 ) }
47
function encodeData( fld ) {
cmd = sprintf( "echo %s | sha1sum", fld )
cmd | getline output
close( cmd )
split( output, arr, " " )
return arr[1]
}
以下是流程细分:
|
$1
重新分配给编码值47
为真(始终)时打印整行这是encodeData
函数细分:
cmd
以将数据提供给sha1sum
getline
cmd
sha1sum
之后有额外的信息,所以我通过split
输出sha1sum
输出的第一个字段。根据您的数据,我得到以下信息:
Accountid|Time|Category|.....
104a1f34b26ae47a67273fe06456be1fe97f75ba|20140101021301|sub1|...
c84270c403adcd8aba9484807a9f1c2164d7f57b|20140101041903|sub2|...
4fa518d8b005e4f9a085d48a4b5f2c558c8402eb|20140101050303|sub1|...
通过调用awk.script data
(或./awk.script data
,如果你打击)
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 \047" fld "\047 | 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[]
数组将脚本与硬编码需要进行哈希处理的字段编号分离,函数的其他参数使它们成为本地,因此在每次调用时始终为null / 0,{{ 1)}在getline上意味着如果失败,你将不会返回先前的成功值(参见http://awk.info/?tip/getline),其余的可能是更多样式/偏好,并且性能有所改善。