Linux awk中的tr命令更改列值

Linux awk中的tr命令更改列值,linux,unix,awk,tr,Linux,Unix,Awk,Tr,我在awk中使用shell脚本TR命令来屏蔽数据。当我在awk中使用tr命令时,下面的示例文件只影响文件的第一行。当我在while循环中使用相同的命令并在其中调用awk命令时,它工作正常,但需要很长时间才能完成。现在,我的要求是屏蔽同一文件(file.txt)中的许多列[例如:$1、$5、$9],这应该会影响整个文件,而不是第一行,我希望更快地屏蔽数据。请告知 cat file.txt ========== abcbchs,degehek abcbchs,degehek abcbchs,dege

我在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、LSKJSHSH
abcbchs,degehek
abcbchs、degehek、LSKJSHSH

输出 efffhs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs,degehek
abcbchs、degehek、LSKJSHSH
abcbchs,degehek
abcbchs、degehek、LSKJSHSH

预期产量 efffhs,degehek
efffhs,degehek
efffhs,degehek
efffhs,degehek
efffhs,degehek
EFFFHS、degehek、LSKJSHSH
efffhs,degehek

efffhs、degehek、lskjshsh

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

的第一、第五和第九个元素。您找到的代码在每个输入行上运行一个外部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

的第一、第五和第九个元素,您忘记了在每次调用后关闭()命令。以下是正确的书写方法:

$ 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调用会增加额外的复杂性,请参阅

根据您的评论,这将显示如何同时修改多个字段(本例中为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
如果您没有任何保证不会出现在输入中的特定控件字符,您可以创建一个不存在的字符串来代替上面的subsp,方法是使用末尾描述的技术,在每次调用后忘记
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调用会增加额外的复杂性,请参阅

根据您的评论,这将显示如何同时修改多个字段(本例中为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

如果您没有任何保证不会出现在输入中的特定控件字符,您可以创建一个不存在的字符串来代替上面的子集,方法是使用

末尾描述的技术,您尝试在awk中运行bash代码,但awk是一种与bash完全不同的语言。如果您想在每一行上运行bash代码,请改用。它看起来有点像您从中复制/粘贴代码,但这并不是一种惯用或常用的方法。@thatotherguy。。虽然循环读取文件的整行内容,但我尝试了它的工作状态,并获得了预期的结果,但时间因素是问题所在。。我曾经用不同的分隔符屏蔽不同类型文件中的数据,列也因文件而异,我希望使用awk是最好的方法。。如果我们在awk命令行中这样做,就会得到预期的结果。然后我将调用我的kshshell脚本..您试图在awk中运行bash代码,但是awk是一种与bash完全不同的语言。如果您想在每一行上运行bash代码,请改用。它看起来有点像您从中复制/粘贴代码,但这并不是一种惯用或常用的方法。@thatotherguy。。虽然循环读取文件的整行内容,但我尝试了它的工作状态,并获得了预期的结果,但时间因素是问题所在。。我曾经用不同的分隔符屏蔽不同类型文件中的数据,列也因文件而异,我希望使用awk是最好的方法。。如果我们在awk命令行中这样做,就会得到预期的结果。然后我将调用我的kshshell脚本..基于OP的切向注释,它尝试修改多个列。作为一个副作用,如果空列少于9个,它会添加新的空列。请尝试使用更多列的输入数据,或将索引更改为仅操作实际拥有的列。@user2449709虽然您对Ed Morton的答案发表了评论,但让我们在此处继续讨论。如果你不能让这个脚本工作,我需要更多的信息来诊断什么是错误的。它对我有用。您可以随意在上玩这个演示,基于OP的切向评论,它尝试修改多个列。作为一个副作用,如果空列少于9个,它会添加新的空列。尝试