在awk中根据字典文件替换字符串

时间:2017-02-08 10:20:42

标签: bash unix awk sed

cat input

aaa paul peter
bbb john mike
ccc paul mike 
bbb paul john

我的字典文件dict:

cat dict

aaa OOO
bbb 111
ccc 222

我需要找到字符串格式input,如果匹配文件dict中的第一列,请将第二列格式文件dict打印到第一列文件input。我可以使用subgsub,但我在dict文件中有数千行(包含不同的字母)。

cat output:

000 paul peter
111 john mike
222 paul mike 
111 paul john

感谢您的帮助。

我的解决方案:

  awk:

awk '{sub(/aaa/,"000",$1); sub(/bbb/,"111",$1); sub(/ccc/,"222",$1)1' input

更新:

如果未找到inputdict的匹配,请保持第一列中的字不变。

猫输入

aaa paul peter
bbb john mike
ccc paul mike 
bbb paul john
ddd paul peter

cat dict

aaa OOO
bbb 111
ccc 222

cat output:

000 paul peter
111 john mike
222 paul mike 
111 paul john
ddd paul peter

4 个答案:

答案 0 :(得分:5)

fedorqui在处理inputdict文件中名称不匹配的注释中建议的更通用的方法可以做,

awk 'FNR==NR {dict[$1]=$2; next} {$1=($1 in dict) ? dict[$1] : $1}1' dict input

我的原始解决方案适用于inputdict文件之间没有错过映射的情况。

awk 'FNR==NR{hash[$2FS$3]=$1; next}{for (i in hash) if (match(hash[i],$1)){print $2, i} }' input dict
OOO paul peter
111 john mike
111 paul john
222 paul mike

我们的想法是创建一个散列图,其索引为$2FS$3,值为$1,即hash["paul peter"]="aaa"等。一旦构造完成,现在查看字典文件查看$1dict的匹配行与input文件的哈希值。如果发现匹配,则根据需要打印内容。

答案 1 :(得分:2)

将我的答案改为:

awk 'NR==FNR{a[$1]=$2;next}{if ($1 in a)print a[$1],$2,$3; else print $0}' dict input

打印

OOO paul peter
111 john mike
222 paul mike
111 paul john
ddd paul peter

使用命令NR == FNR,以下命令仅在第一个文件上执行。每行都存储在数组a中,键为$ 1,值为$ 2。然后$ 1 in a从第二个文件获取$ 1,并查看是否可以在数组a中找到该值。如果是,那么[$ 1]打印数字,$ 2和$ 3打印名称。现在有一个额外的else子句,如果找不到匹配项,它会保持输入的整行输出。

答案 2 :(得分:1)

我认为你可以有效地使用GNU join

sort input > sorted_input
sort dict > sorted_dict
join sorted_dict sorted_input -o 1.2,2.2,2.3

使用您的示例数据提供以下输出(注意排序修改了输出,但是join必须工作):

OOO paul peter
111 john mike
111 paul john
222 paul mike

所有这些都依赖于连接字段是每个文件的第一个,否则您需要指定文件应该连接到哪个字段。

-o参数是格式输出规范,并且是指输出中我们想要的每个文件的字段:dict的第二个字段,后跟每个字段,但第一个字段{ {1}}。

您已经提到input中可能找不到某些密钥,并且您希望保留dict的第一个字段中的值。有input选项来处理它,但它会混淆我们的输出,所以我认为更容易做两次执行,第一次执行输出每个文件中对应的行,第二次执行在-a中处理没有对应的行:

dict

如果由于文件的大小而增加了太多的开销,则应该使用$ join sorted_dict sorted_input -o 1.2,2.2,2.3; join sorted_dict sorted_input -v 2 OOO paul peter 111 john mike 111 paul john 222 paul mike ddd paul peter 执行单个执行,而不使用输出规范,然后使用-a 2转换结果,{ {1}}或其他东西来处理缺少字段的行。

答案 3 :(得分:1)

对于操作来说,awk更快,但这是一个纯粹的bash解决方案。

#!/bin/bash

typeset -A dict

function add_dict()
{
   dict[$1]=$2
}

add_dict aaa 000
add_dict bbb 111
add_dict ccc 222

while read row
do
   column=(${row//:/ })
   if [ "${dict[${column[0]}]}" ];then
      echo ${dict[${column[0]}]} ${column[1]} ${column[2]}
   else
      echo ${column[0]} ${column[1]} ${column[2]}
   fi 
done < /tmp/1M.txt

#1 Million lines processed in
#real   0m40.173s
#user   0m37.668s
#sys    0m2.462s

#time awk 'NR==FNR{a[$1]=$2;next}{if ($1 in a)print a[$1],$2,$3; else print $0}' dict 1M.txt > processed.txt

#real   0m0.281s
#user   0m0.242s
#sys    0m0.024s