【问题标题】:Marking tree file with a name用名称标记树文件
【发布时间】:2021-08-16 11:33:33
【问题描述】:

我有一个像这样的 Newick/Phylip 格式文件

(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/'

但它没有奏效。有什么建议吗?

【问题讨论】:

  • 请不要使用块引用格式化您的数据样本,而是使用代码块来保留换行符。
  • 为什么sed '/'Dog'/s/Dog/#Del/'中有这么多单引号?你写道你“有多个具有不同值的文件,并且还必须对其他动物进行多次更改”但你只尝试了Dog#Del你能解释一下吗更好一点你想做什么?你在哪里指定什么动物,什么值,什么文件等等?
  • 我可以把这段代码放到循环中,例如:cat list |同时读取 r;做 sed '/'$r'/s/$r/#Del/' >$r.out;完成
  • 请编辑您的问题以在问题本身中添加缺失的信息,以便对其他人也有用。请尽量与您接受的答案保持一致。例如,您的最后一条评论不是:您想从文件中还是从命令行中获取动物名称?您想要每只动物一个结果文件还是只需要一个结果文件?

标签: shell awk


【解决方案1】:

使用一次 GNU awk 调用(用于 gensub() 和单词边界)一次更新任意数量的目标:

$ 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);

【讨论】:

    【解决方案2】:

    如果您要修改的数据位于名为 myFile 的文件中,那么您的动物是简单的单词(只是字母),每行一个,位于名为 list 的文件中,那么您可以在 shell 循环中执行您想要的操作使用 GNU sed,就像您已经开始使用的那样:

    cat list | while read animal; do
      sed -E 's/\<('"$animal"':[0-9.]*)/\1#Del/' myFile > "$animal".out
    done
    

    对于列表中的每个animal,将创建一个名为animal.out 的文件,其中包含修改后的数据。

    GNU sed 命令使用扩展​​正则表达式 (-E)。

    要搜索和替换的正则表达式 (\&lt;('"$animal"':[0-9.]*)) 以单词开头 (\&lt;) 开头,这样动物名称就不会匹配另一个名称中间的任何位置。左括号开始记录匹配的子表达式;右括号结束录制。我们使用单引号和双引号来允许扩展 shell 变量 animal (1)。然后我们找到一个冒号,后跟任意数量的数字或句点 ([0-9.]*)。

    替换表达式使用第一个(也是唯一一个)记录的匹配子表达式 (\1)。

    我们可以改进正则表达式中与动物名称后面的数字匹配的部分:[0-9]*\.[0-9]*,以保证它只包含一个句点。如果您对这些数字有更多了解,我们可以更具体:[0-9]+\.[0-9]+ 如果您在句点前后始终至少有一位数字。

    (1) 如果你的动物名字真的很简单的话,$animal 周围的双引号是没有用的;但是双引号这种参数扩展是一种很好的做法,它不会造成伤害。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 2014-11-17
      相关资源
      最近更新 更多