如何使用sed,bash或awk替换字符串中最后一次出现的 - )?

时间:2016-02-27 11:50:17

标签: bash awk sed

示例输入文件:

xxx-xxx(-)        xxx   xxx  xxx      -       2e-15   Cytochrome b-c1 complex subunit 9       xxx   xxx:241-77(-)
xxx-xxx(+)        xxx   xxx  xxx      +       3e-24   Probable endo-beta-1,4-glucanase D       xxx   xxx:241-77(+)

我一直在尝试sed,但没有成功。我可以看到以下两件事情有效:

rev file|sed -e 's/-/M/'|rev
rev file|sed -e 's/)/M/'|rev

但是,-)一起不起作用:

rev file|sed -e 's/-)/M/'|rev

3 个答案:

答案 0 :(得分:1)

这是因为rev"反转"订单,你知道吗?反转版本中不会出现-);它在反向文件中为)-

rev file|sed -e 's/)-/M/'|rev

答案 1 :(得分:1)

你不需要使用管道链或花哨操作的多个命令 - 因为seds regexp是贪婪的,你只需要:

$ sed 's/\(.*\)-)/\1M/' file
xxx-xxx(-)        xxx   xxx  xxx      -       2e-15   Cytochrome b-c1 complex subunit 9       xxx   xxx:241-77(M
xxx-xxx(+)        xxx   xxx  xxx      +       3e-24   Probable endo-beta-1,4-glucanase D       xxx   xxx:241-77(+)

答案 2 :(得分:0)

用纯(GNU)sed

“替换 n th-to-last one of something”的一般方法
  1. 我们希望将“某些内容”(在本例中为-))替换为输入中未找到的唯一内容,例如~B。为确保此序列不在您的输入中,我们先将所有~替换为~A

    sed 's/~/~A/g' infile
    
  2. -)替换为~B的所有“内容”,我们现在知道它将是唯一的:

    sed 's/-)/~B/g'
    

    现在您的输入文件看起来像这样(稍加编辑,因此它符合此处的线宽):

    xxx-xxx(~B  xxx   -   2e-15   Cytochrome b-c1 complex subunit 9   xxx   xxx:241-77(~B
    xxx-xxx(+)  xxx   +   3e-24   Probable endo-beta-1,4-glucanase D   xxx   xxx:241-77(+)
    
  3. 下一个命令执行此操作:“只要该行具有 n + ~B的1,请将第一个替换为-)。{{ 1}}和:a是一个分支到条件分支的标签(如果发生了替换,则转到标签ta):

    :a

    对于 n = 1的情况,即我们想要替换最后一次出现,量词sed ':a;/~B\(.*~B\)\{1\}/s/~B/-)/;ta' 当然不需要,但可以替换为其他值< EM>名词的

    输入文件现在有一个唯一的\{1\},其中最后一个~B曾经是:

    -)
  4. 我们替换单xxx-xxx(-) xxx - 2e-15 Cytochrome b-c1 complex subunit 9 xxx xxx:241-77(~B xxx-xxx(+) xxx + 3e-24 Probable endo-beta-1,4-glucanase D xxx xxx:241-77(+)

    ~B

    导致

    sed 's/~B/M/'
    
  5. xxx-xxx(-) xxx - 2e-15 Cytochrome b-c1 complex subunit 9 xxx xxx:241-77(M xxx-xxx(+) xxx + 3e-24 Probable endo-beta-1,4-glucanase D xxx xxx:241-77(+) 的其余部分现在可以替换为~B(在这种情况下为无操作):

    -)
  6. 最后,我们撤消第一个替换(对于此示例没有任何影响,因为输入没有sed 's/~B/-)/g' 开头):

    ~
  7. 全部在一行中:

    sed 's/~A/~/g'
    

    或者,为了便于阅读,多行:

    sed 's/~/~A/g;s/-)/~B/g;:a;/~B\(.*~B\)\{1\}/s/~B/-)/;ta;s/~B/M/;s/~B/-)/g;s/~A/~/g' infile
    

    当然,对于 n = 1的情况,有更简单的解决方案,例如Ed Morton's answer