我在awk中用我的shell脚本TR命令来掩盖数据。当我在awk中使用tr命令时,下面的示例文件仅影响我文件的第一行。当我在 while 循环中使用相同的内容并在其中调用awk命令时,它的工作正常,但需要很长时间才能完成。现在我的要求我想要在同一个文件(file.txt)中屏蔽许多列[例如:$ 1,$ 5,$ 9],这应该影响整个文件而不是第一行,我想要更快地实现这一点来掩盖数据。请指教
cat file.txt
========
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek,lskjsjshsh
abcbchs,degehek
abcbchs,degehek,lskjsjshsh
awk -F"," -v OFS="," '{ "echo \""$1"\" | tr \"a-c\" \"e-f\" | tr \"0-5\" \"6-9\"" | getline $1 }7' file.txt
effffhs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek,lskjsjshsh
abcbchs,degehek
abcbchs,degehek,lskjsjshsh
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek,lskjsjshsh
effffhs,degehek
effffhs,degehek,lskjsjshsh
答案 0 :(得分:3)
您找到的代码在每个输入行上运行外部shell命令管道。就像你发现的那样,这是一种非常低效的方式来做你要求的事情。 Awk根本不是这项任务的理想选择。也许试试Perl。
perl -F, -lane '$F[$_] =~ tr/a-c/e-f/ =~ tr/0-5/6-9/ for (0, 4, 8); print join(",", @F)' file
-F,
选项与Awk类似,但Perl不会自动拆分输入行。使用-a
,分成名为@F
的数组,并使用-n
循环遍历所有输入行。 -l
可以方便地从每个输入行中删除换行符,并在打印时添加一行。
注意列是如何编号的,而不是一个,就像在Awk中一样;所以for
循环中的索引访问@F
的第一,第五和第九个元素。
答案 1 :(得分:2)
每次调用后,您忘记了close()
命令。这是写它的正确方法:
$ cat tst.awk
BEGIN { FS=OFS="," }
{
cmd="echo '" $1 "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
$1 = ( (cmd | getline line) > 0 ? line : $1 )
close(cmd)
print
}
$ awk -f tst.awk file
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek
effffhs,degehek,lskjsjshsh
effffhs,degehek
effffhs,degehek,lskjsjshsh
你也没有保护自己免受getline失败,因此getline调用的额外复杂性,请参阅http://awk.info/?tip/getline。
鉴于您的意见,这显示了如何同时修改多个字段(在本例中为1,3和5):
$ cat tst.awk
BEGIN { FS=OFS="," }
{
cmd = "echo '" $0 "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
new = ( (cmd | getline line) > 0 ? line : $1 )
close(cmd)
split(new,tmp)
for (i in tmp) {
if (i ~ /^(1|3|5)$/) {
$i = tmp[i]
}
}
print
}
$ cat file
abc,abc,abc,abc,abc
abc,abc,abc,abc,abc,abc,abc
abc,abc,abc,abc,abc,abc
abc,abc,abc,abc
$ awk -f tst.awk file
eff,abc,eff,abc,eff
eff,abc,eff,abc,eff,abc,abc
eff,abc,eff,abc,eff,abc
eff,abc,eff,abc
处理输入数据中的引号:
$ cat tst.awk
BEGIN { FS=OFS="," }
{
gsub(/'/,SUBSEP)
cmd = "echo '" $0 "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
new = ( (cmd | getline line) > 0 ? line : $1 )
close(cmd)
split(new,tmp)
for (i in tmp) {
if (i ~ /^(1|3|5)$/) {
$i = tmp[i]
}
}
gsub(SUBSEP,"'")
print
}
$ cat file
a'c,abc,a"c,abc,abc
abc,a'c,abc,a"c,abc,abc,abc
abc,abc,abc,abc,abc,abc
abc,abc,abc,abc
$ awk -f tst.awk file
e'f,abc,e"f,abc,eff
eff,a'c,eff,a"c,eff,abc,abc
eff,abc,eff,abc,eff,abc
eff,abc,eff,abc
如果您没有任何保证不会出现在输入中的特定控件字符,则可以使用https://stackoverflow.com/a/29237745/1745001末尾描述的技术创建一个不存在的字符串来代替上面的SUBSEP使用