在AWK tr命令来改变列值(tr command in awk to change the col

2019-10-22 08:44发布

我在AWK用我的shell脚本TR命令来掩盖的数据。 下面的示例文件会影响我的文件只有第一线,当我在AWK使用tr命令。 当我使用相同的while循环,并呼吁它里面awk命令那么它工作正常,但它采取非常长的时间来完成。 现在,我的要求,我想掩盖许多列[例如:$ 1,$ 5,$ 9]在同一个文件(file.txt的),这应该不会影响整个文件不是第一线,我想尽可能快掩盖达到这个数据。 请指教

猫file.txt的
========
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek,lskjsjshsh
abcbchs,degehek
abcbchs,degehek,lskjsjshsh

OUTPUT

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

Answer 1:

你忘了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

如果你没有有保证不会出现在你输入的任何特殊字符的控制,您可以通过上述使用在结束中描述的技术创建一个不存在的字符串,而不是SUBSEP的使用https://stackoverflow.com/一个/一百七十四万五千零一分之二千九百二十三万七千七百四十五



Answer 2:

你找到的代码运行在每个输入行的外壳命令管道。 就像你发现,这是一个非常低效的方式做你的要求。 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



文章来源: tr command in awk to change the column values
标签: linux unix awk tr