我有一个Newick/phillip格式的文件,如下所示
(Chicken:0.247775,
Mouse:0.091619,
(GuineaPig:0.174006,
((OwlMonkey:0.069823,
((Chimp:0.009091,
Human:0.009091):0.025108,
GreenMonkey:0.018831):0.015025):0.029561,
((Sheep:0.087386,
Pig:0.039886):0.022893,
Dog:0.068016):0.005950):0.023011):0.006297);
我需要将分支Dog标记为Dog:0.068016#Del
(Chicken:0.247775,
Mouse:0.091619,
(GuineaPig:0.174006,
((OwlMonkey:0.069823,
((Chimp:0.009091,
Human:0.009091):0.025108,
GreenMonkey:0.018831):0.015025):0.029561,
((Sheep:0.087386,
Pig:0.039886):0.022893,
Dog:0.068016#Del):0.005950):0.023011):0.006297);
这很容易用sed 's/Dog:0.068016/Dog:0.068016#Del/g'
完成但是我有多个具有不同值的文件,并且必须对其他动物进行多次更改,所以我尝试使用以下方法
sed '/'Dog'/s/Dog/#Del/'
但它没有工作。有什么建议吗?
使用单个调用GNU awk(用于gensub()和word boundaries)来一次更新尽可能多的目标:
$ cat tst.awk
BEGIN {
split(t,tmp)
for (i in tmp) {
tgts[tmp[i]]
}
}
{
for (tgt in tgts) {
$0 = gensub("\<(" tgt ":[0-9.]+)","\1#Del",1)
}
print
}
$ awk -v t='Dog' -f tst.awk file
(Chicken:0.247775,
Mouse:0.091619,
(GuineaPig:0.174006,
((OwlMonkey:0.069823,
((Chimp:0.009091,
Human:0.009091):0.025108,
GreenMonkey:0.018831):0.015025):0.029561,
((Sheep:0.087386,
Pig:0.039886):0.022893,
Dog:0.068016#Del):0.005950):0.023011):0.006297);
$ awk -v t='Dog Human Mouse' -f tst.awk file
(Chicken:0.247775,
Mouse:0.091619#Del,
(GuineaPig:0.174006,
((OwlMonkey:0.069823,
((Chimp:0.009091,
Human:0.009091#Del):0.025108,
GreenMonkey:0.018831):0.015025):0.029561,
((Sheep:0.087386,
Pig:0.039886):0.022893,
Dog:0.068016#Del):0.005950):0.023011):0.006297);
如果你要修改的数据在一个名为myFile
的文件中,你的动物是简单的单词(只是字母),每行一个,在一个名为list
的文件中,那么你可以在GNUsed
的shell循环中做你想做的事情,就像你已经开始的那样:
cat list | while read animal; do
sed -E 's/<('"$animal"':[0-9.]*)/1#Del/' myFile > "$animal".out
done
对于列表中的每个animal
,将创建一个名为animal.out
的文件,其中包含修改后的数据。
GNUsed
命令使用扩展正则表达式(-E
)。
要搜索和替换的正则表达式(<('"$animal"':[0-9.]*)
)以单词开头(<
)开始,使得动物名称在另一个名称中间的任何地方都不匹配。左括号开始记录匹配的子表达式;右括号结束录音。我们使用单引号和双引号来扩展shell变量animal
(1)。然后我们找到一个冒号,后面跟着任意数量的数字或句点([0-9.]*
)。
替换表达式使用第一个(也是唯一一个)记录的匹配子表达式(1
)。
我们可以改进正则表达式中与动物名字后面的数字匹配的部分:[0-9]*.[0-9]*
,以保证它只包含一个句点。如果你对这些数字有更多的了解,我们可以更具体地说:[0-9]+.[0-9]+
,如果你总是在句点前后至少有一个数字。
(1)如果你的动物名字真的是简单的单词,$animal
周围的双引号是无用的;但是,对这种类型的参数展开进行双引号引用是一种很好的做法,而且不会有什么坏处。