Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 根据awk中的字典文件替换字符串_Bash_Unix_Awk_Sed - Fatal编程技术网

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

Bash 根据awk中的字典文件替换字符串,bash,unix,awk,sed,Bash,Unix,Awk,Sed,和我的字典文件dict: cat input aaa paul peter bbb john mike ccc paul mike bbb paul john 我需要找到字符串格式input,如果匹配文件dict中的第一列,则将第二列格式文件dict打印到第一列文件input。我可以使用sub和gsub,但我在dict文件中有数千行(用不同的字母) 谢谢你的帮助 我的解决方案: cat output: 000 paul peter 111 john mike 222 paul mike

和我的字典文件dict:

cat input

aaa paul peter
bbb john mike
ccc paul mike 
bbb paul john
我需要找到字符串格式
input
,如果匹配文件
dict
中的第一列,则将第二列格式文件
dict
打印到第一列文件
input
。我可以使用
sub
gsub
,但我在
dict
文件中有数千行(用不同的字母)

谢谢你的帮助

我的解决方案:

cat output:

000 paul peter
111 john mike
222 paul mike 
111 paul john
更新:

如果在
dict
中的
input
中未找到匹配项,请保持第一列中的单词不变

cat输入

  awk:

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

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

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
这将为您的示例数据提供以下输出(请注意,排序修改了输出,但这是
join
工作所必需的):

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

-o
参数是一种格式输出规范,指的是输出中所需的每个文件的字段:
dict
的第二个字段,后面是每个字段,但
输入的第一个字段除外

您提到了一些键可能在
dict
中找不到,您希望保留
input
的第一个字段中的值。有一个
-一个
选项来处理这个问题,但它会干扰我们的输出,所以我认为更容易的方法是执行两个执行,第一个执行在每个文件中输出具有对应关系的行,第二个执行在
dict
中处理不具有对应关系的行:

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

如果由于文件的大小而增加了太多的开销,则应改为使用
-a2
执行一次,而不使用输出规范,然后使用
sed
转换结果,
awk
或处理缺少字段的行的其他方法。

注释中建议的处理
输入
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

下面我的原始解决方案适用于
输入
dict
文件之间没有遗漏映射的情况

awk 'FNR==NR {dict[$1]=$2; next} {$1=($1 in dict) ? dict[$1] : $1}1' dict input
其思想是创建一个散列映射,索引为
$2FS$3
,值为
$1
,即
散列[“paul peter”]=“aaa”
,等等。一旦构建了该映射,现在字典文件将查看
dict
$1
的匹配行以及
input
文件中的散列值。如果找到匹配项,请根据需要打印内容。

将我的答案更改为:

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
印刷品

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

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

awk的操作速度快了很多,但这里有一个纯bash解决方案

OOO paul peter
111 john mike
222 paul mike
111 paul john
ddd paul peter
#/bin/bash
打字机-口述
函数add_dict()
{
dict[$1]=$2
}
添加目录aaa 000
添加内容bbb 111
添加目录ccc 222
读行时
做
列=(${row/://})
如果[“${dict[${column[0]}]}”];然后
echo${dict[${column[0]}]}${column[1]}${column[2]}
其他的
echo${column[0]}${column[1]}${column[2]}
fi
完成processed.txt
#实0.281s
#用户0.242s
#系统0m0.024s

input
如何在
bbb
中有两个条目,它不应该是唯一的吗?第一列中的任何条目都不能重复多次。不同之处在其他栏中。@fedorqui我试了一下。但是这项工作如果我只有几句话的话。我想读一下dict文件。我不确定我是否可以使用awk..对于与dict文件不匹配的行,应该怎么办?@Geroge您能更新示例数据和相关输出以反映这一点吗?考虑到这一点,我认为我的答案需要更新。谢谢。如果我有不同数量的列,比如输入有500行,dict有50K行,行还是列?行,是的,它会工作;我想它应该和您可以编写的任何
awk
脚本一样高效,但您肯定应该测试它。由于列太多,
-o
格式规范编写起来会很麻烦,而我会依赖于
cut
的范围(例如
cut-d'-f2-
,它只会删除第一个字段)。GNU工具箱中总是有一个用于执行任务的工具!(当然它通常是
awk
:p)你可能可以说
{$1=(a中的$1)?dict[$1]:$1}1
,使它更简洁。@Inian我用
awk'FNR==NR{dict[$1]=2;next}{$1=(dict中的$1=):dict输入
,我认为你是在过度复制索引。@fedorqui。谢谢^^是的,我指的是这个答案。使用字段2和3似乎有点不必要。还有,为什么要先检查输入,然后再检查dict?映射是通过dict完成的,所以应该先加载它,然后使用它的值来更改输入中的数据。@fedorqui:在更改之前,我碰巧在第一个需求中使用了这种方法,所以碰巧我没有使它灵活地用于其他情况。我能用你的评论作为我答案的更新吗?我明白了。由于它不灵活,并且比没有任何循环的简单数组中的
val更复杂,我认为首先解析
dict
显然是最简单的方法@费多基:没错!
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
#!/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