我正在尝试使用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
答案 0 :(得分:5)
读取第一个文件并存储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
映射到Dusky
,2
到Flag
,... {$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 :(得分: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
答案 2 :(得分: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