sed:替换多个模式,但不能使用相同的字符串

orn*_*nit 7 bash sed

是否可以在同一命令中将多个模式更改为不同的值?让我说我有

A B C D ABC
Run Code Online (Sandbox Code Playgroud)

我想将每个A改为1,每个B改为2,每个C改为3

所以输出会是

1 2 3 D 123
Run Code Online (Sandbox Code Playgroud)

因为我有3个模式要改变,我想避免单独替换它们.我以为会有类似的东西

sed -r s/'(A|B|C)'/(1|2|3)/ 
Run Code Online (Sandbox Code Playgroud)

但当然这只是将A或B或C替换为(1 | 2 | 3).我应该提一下,我的真实模式比那更复杂......

谢谢!

hek*_*mgl 13

容易sed:

sed 's/WORD1/NEW_WORD1/g;s/WORD2/NEW_WORD2/g;s/WORD3/NEW_WORD3/g'
Run Code Online (Sandbox Code Playgroud)

您可以通过a在同一行上分隔多个命令 ;


更新

可能这太容易了.NeronLeVelu指出上述命令可能导致不需要的结果,因为第二次替换甚至可能触及第一次替换的结果(依此类推).

如果您关心这一点,可以使用该t命令避免此副作用.t如果之前发生了成功的替换,则命令将分支到标签(如果缺少标签,则分支到脚本的末尾).

我们不使用标签,因为如果一个成功,我们不希望进一步的替换:

sed 's/WORD1/NEW_WORD1/g;t;s/WORD2/NEW_WORD2/g;t;s/WORD3/NEW_WORD3/g'  
Run Code Online (Sandbox Code Playgroud)


cho*_*oba 3

简单的 Perl 语言:

perl -pe '%h = (A => 1, B => 2, C => 3); s/(A|B|C)/$h{$1}/g'
Run Code Online (Sandbox Code Playgroud)

如果您使用更复杂的模式,请将更具体的模式放在备用列表中更通用的模式之前。按长度排序可能就足够了:

perl -pe 'BEGIN { %h = (A => 1, AA => 2, AAA => 3);
              $re = join "|", sort { length $b <=> length $a } keys %h; }
          s/($re)/$h{$1}/g'
Run Code Online (Sandbox Code Playgroud)

要添加单词或行边界,只需将模式更改为

/\b($re)\b/
# or
/^($re)$/
# resp.
Run Code Online (Sandbox Code Playgroud)