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
。我可以使用sub
和gsub
,但我在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
更新:
如果未找到input
中dict
的匹配,请保持第一列中的字不变。
猫输入
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
答案 0 :(得分:5)
fedorqui在处理input
和dict
文件中名称不匹配的注释中建议的更通用的方法可以做,
awk 'FNR==NR {dict[$1]=$2; next} {$1=($1 in dict) ? dict[$1] : $1}1' dict input
我的原始解决方案适用于input
和dict
文件之间没有错过映射的情况。
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"
等。一旦构造完成,现在查看字典文件查看$1
中dict
的匹配行与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)
#!/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