awk 中的 tr 命令更改列值

tr command in awk to change the column values

我在 shell 脚本中使用 awk 中的 TR 命令来屏蔽数据。当我在 awk 中使用 tr 命令时,下面的示例文件仅影响我的文件的第一行。当我在 while 循环中使用相同的方法并在其中调用 awk 命令时,它工作正常但需要很长时间才能完成。现在我的要求是我想在同一个文件(file.txt)中屏蔽许多列[例如:$1、$5、$9],这应该会影响整个文件而不是第一行,我想尽可能快地实现这一点屏蔽数据。请指教

猫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 \"""\" | tr \"a-c\" \"e-f\" | tr \"0-5\" \"6-9\"" | getline  }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

您找到的代码在每个输入行上运行一个外部 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.

的第一个、第五个和第九个元素

您忘记在每次调用后 close() 命令。正确的写法是:

$ cat tst.awk
BEGIN { FS=OFS="," }
{
    cmd="echo '"  "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
     = ( (cmd | getline line) > 0 ? line :  )
    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 '" [=11=] "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
    new = ( (cmd | getline line) > 0 ? line :  )
    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 '" [=12=] "' | tr 'a-c' 'e-f' | tr '0-5' '6-9'"
    new = ( (cmd | getline line) > 0 ? line :  )
    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

如果您没有任何保证不会出现在您的输入中的特定控制字符,您可以使用 [=15 末尾描述的技术创建一个不存在的字符串来代替上面的 SUBSEP =]