【问题标题】:Multiple substitutions on the same file - awk同一文件上的多个替换 - awk
【发布时间】:2015-01-29 10:37:05
【问题描述】:

我正在尝试使用 awk 单行脚本对同一个文件进行多次替换。 用于变量赋值的文件如下:

> cat names 
1 Dusky
2 Flag
3 Mon

我想在这个文件中进行替换:

> cat file.txt 
  1        1   0.6248 0.3752 
  2        2   0.0430 0.9570 
  3        3   0.0624 0.9376

我尝试过的是:

while read num name; do 
    awk -v J=$num -v R=$name '{if (match($1, J)) $2=R; print;}' file.txt; 
done < names

但此代码会打印要替换的每一行的输入文件。

1 Dusky 0.6248 0.3752
  2        2   0.0430 0.9570 
  3        3   0.0624 0.9376 
  1        1   0.6248 0.3752 
2 Flag 0.0430 0.9570
  3        3   0.0624 0.9376 
  1        1   0.6248 0.3752 
  2        2   0.0430 0.9570 
3 Mon 0.0624 0.9376

我怎样才能让它只打印一次被替换的行? 可以在 awk 或 perl 中。

期望的输出:

1 Dusky 0.6248 0.3752
2 Flag 0.0430 0.9570
3 Mon 0.0624 0.9376

【问题讨论】:

  • 所以您想将file.txt 中的第二列替换为names 中的对应名称?列之间的分隔符是什么?
  • 没错。分隔符是空格,但它可以是多个空格分隔字段。

标签: perl replace awk


【解决方案1】:

怎么样

$ awk 'NR==FNR{line[$1]=$2; next} {line[$1]=line[$1]" "$3" "$4} END{for( i in line) print i, line[i]}' names file
1 Dusky 0.6248 0.3752
2 Flag 0.0430 0.9570
3 Mon 0.0624 0.9376

【讨论】:

    【解决方案2】:

    读取第一个文件并存储 ID 怎么样?然后,将第二个文件中的第二个字段替换为匹配的名称/id。

    awk 'FNR==NR {a[$1]=$2; next} {$2=a[$2]; print}' names f
    

    对于给定的输入,它会返回:

    1 Dusky 0.6248 0.3752
    2 Flag 0.0430 0.9570
    3 Mon 0.0624 0.9376
    

    说明

    • FNR==NR {a[$1]=$2; next} 读取第一个文件时,将第二个字段存储在索引为第一个字段的数组中。这样,1 映射到 Dusky2Flag,...
    • {$2=a[$2]; print} 读取第二个文件时,将第二个字段替换为第一个文件中对应的 id。然后,打印。这可以更惯用地写成{$2=a[$2]}1

    请注意,您可以添加安全检查:如果确实存在,只需替换第二个文件上的第二个字段:

    awk 'FNR==NR {a[$1]=$2; next} {if ($2 in a) $2=a[$2]} 1' names f
    

    【讨论】:

    • 您甚至可以简写并在第二个操作块之后使用1,而不是print
    • 太棒了。非常好的单线。这也表明我需要研究更多的 FNR 和 NR 变量...
    • @PedroA 阅读Idiomatic awk。你会在那里找到多汁的东西!
    • 可以缩短为 awk 'FNR==NR {a[$1]=$2; next}$2 in a{$2=a[$2]} 1' 或假设数字是唯一的,它可以缩短为 awk '$2 in a&amp;&amp;$2=a[$2];{a[$1]=$2}'
    【解决方案3】:

    从命令行使用 perl,

    perl -lane'
      BEGIN{ local @ARGV=pop; %h= map split,<> }
      $_ = $h{$_} //$_ for $F[1]; print "@F"
    ' file.txt names
    

    输出

    1 Dusky 0.6248 0.3752
    2 Flag 0.0430 0.9570
    3 Mon 0.0624 0.9376
    

    【讨论】:

    • 感谢 perl 单行。 +1
    • @PedroA 如果names 文件中没有第二列,则第二列保持不变。
    • 不错.. 一开始我发现$_ = $h{$_} //$_ for $F[1] 有点神秘,但后来我意识到$_for 循环中的引用。所以它相当于$F[1] = $h{$F[1]} // $F[1].. 还在学习 Perl 中的神奇技巧 :)
    • @HåkonHægland 是的,$F[1] 使用 for 对其进行别名/主题化。它可能有时在处理长变量或重复变量时很有用。
    猜你喜欢
    • 1970-01-01
    • 2017-05-12
    • 1970-01-01
    • 2023-03-07
    • 2014-11-13
    • 2018-09-14
    • 1970-01-01
    • 2011-12-12
    • 2019-03-22
    相关资源
    最近更新 更多