【问题标题】:How to translate a column value in the file using awk with tr command in unix如何在 unix 中使用 awk 和 tr 命令转换文件中的列值
【发布时间】:2014-02-14 23:58:36
【问题描述】:

详情:

输入文件:file.txt

P123456789,COLUMN2
P123456790,COLUMN2
P123456791,COLUMN2

预期输出:

Z678999999,COLUMN2
Z678999995,COLUMN2
Z678999996,COLUMN2

如果我尝试使用变量,它会给出正确的结果。

(i.e) /tmp>echo "P123456789"|tr "0-9" "5-9"|tr "A-Z" "X-Z"
Z678999999

但是如果我使用 awk 命令,它不会给出结果而是给出错误:

/tmp>$ awk 'BEGIN { FS=OFS="," } { $1=echo $1|tr "0-9" "5-9"|tr "A-Z" "X-Z";$2="COLUMN2"); print }' /tmp/file.txt >/tmp/file.txt.tmp
awk: BEGIN { FS=OFS="," } { $1=echo $1|tr "0-9" "5-9"|tr "A-Z" "X-Z";$2="COLUMN2"); print }
awk:                                   ^ syntax error
awk: BEGIN { FS=OFS="," } { $1=echo $1|tr "0-9" "5-9"|tr "A-Z" "X-Z";$2="COLUMN2"); print }
awk:                                                  ^ syntax error
awk: BEGIN { FS=OFS="," } { $1=echo $1|tr "0-9" "5-9"|tr "A-Z" "X-Z";$2="COLUMN2"); print }
awk:                                                                             ^ syntax error

有人可以帮忙吗?

【问题讨论】:

  • awk 不是外壳,就像 C 不是外壳一样。你不能从 awk 程序调用 shell 命令,就像你不能从 C 程序调用它一样。
  • 查看此链接:calling-an-executable-program-using-awk。您也可以查找getline 的答案(参见 Kent 的答案),或者学习足够的 awk 来完全操作 awk 中的数据。

标签: awk


【解决方案1】:

做你想做的,不改变你的逻辑:

awk 行:

awk -F, -v OFS="," '{ "echo \""$1"\"|tr \"0-9\" \"5-9\"|tr \"A-Z\" \"X-Z\"" |getline $1}7'

使用您的数据:

kent$  echo "P123456789,COLUMN2
P123456790,COLUMN2
P123456791,COLUMN2"|awk -F, -v OFS="," '{ "echo \""$1"\"|tr \"0-9\" \"5-9\"|tr \"A-Z\" \"X-Z\"" |getline $1}7'                                                              
Z678999999,COLUMN2
Z678999995,COLUMN2
Z678999996,COLUMN2

【讨论】:

  • 仍然报错:/tmp>$ cat aml_test.txt|awk -F, -v OFS="," '{ "echo \""$1"\"|tr \"0 -9\" \"5-9\"|tr \"A-Z\" \"X-Z\"" |getline $1}7' sh: -c: line 0: 寻找匹配的 `"' 时意外的 EOF sh: - c:第 1 行:语法错误:文件意外结束 P123456789,COLUMN2 P123456790,COLUMN2 P123456791,COLUMN2
  • 在我的回答中尝试相同的命令,看看它是否有效。不知道你的数据长什么样。 @Murali
  • +1,但最后神秘的7 是什么?只是一个非零整数来创建导致打印当前行的始终正确的模式?你的意思是使用1
  • @mklement0 是的。但是按 7 对我来说比 1 更容易
  • 肯特,你能帮忙吗?当我使用与上面给出的相同的命令运行您的命令时,我收到了错误
【解决方案2】:
$ cat tst.awk
function tr(old,new,str,        oldA,newA,strA,i,j) {
    split(old,oldA,"")
    split(new,newA,"")
    split(str,strA,"")
    str = ""
    for (i=1;i in strA;i++) {
        for (j=1;(j in oldA) && !sub(oldA[j],newA[j],strA[i]);j++)
            ;
        str = str strA[i]
    }
    return str
}

BEGIN { FS=OFS="," }
{ print tr("P012345678","Z567899999",$1), $2 }

$ awk -f tst.awk file
Z678999999,COLUMN2
Z678999995,COLUMN2
Z678999996,COLUMN2

【讨论】:

    【解决方案3】:

    很遗憾,AWK 没有内置翻译功能。你可以像Ed Morton 那样写一个,但我会寻求(并强烈推荐)一个更强大的工具。例如,Perl 可以使用 autosplit (-a) 命令开关处理字段:

    -a 与 -n 或 -p 一起使用时打开自动拆分模式。 @F 数组的隐式拆分命令是在 -n 或 -p 产生的隐式 while 循环。

    您可以输入perldoc perlrun了解更多详情。

    这是我的解决方案:

    perl -F, -lane '$F[0] =~ tr/0-9/5-9/; $F[0] =~ tr/A-Z/X-Z/; print join (",", @F)' file.txt
    

    结果:

    Z678999999,COLUMN2
    Z678999995,COLUMN2
    Z678999996,COLUMN2
    

    【讨论】:

    • 谢谢史蒂夫!!!精彩的。我发现 awk 是作为 C 程序运行的,所以它不允许使用 unix 命令,所以我通过系统命令尝试了它对我有用的翻译部分。但我相信我的方法需要处理时间,而不是我会按照你的方法进行
    • 即使是下面的方法我们也可以遵循,但取决于我们应该选择的方法的处理速度。 >/tmp>$ awk 'BEGIN { FS=OFS="," } { $1=system("echo "$1"|tr '0-9' '5-9'|tr 'A-Z' 'X-Z'" );$2="COLUMN2"} ' /tmp/file.txt >结果:=========== Z678999999 Z678999995 Z678999996
    • @Murali: system() 返回命令的退出代码,而不是它的标准输出;请参阅@Kent 的答案,以使用 getline 在变量中捕获 shell 命令输出。
    • @Murali:如果你有时间,我很想看看三个答案的基准。我敢打赌 Perl 是最慢的,但差异可能微不足道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多