awk中的tr命令可以更改列值

时间:2015-03-24 18:56:29

标签: linux unix awk tr

我在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

2 个答案:

答案 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使用