如何用sed一次replace多个模式?

假设我有'abbc'string,我想replace:

  • ab – > bc
  • bc – > ab

如果我尝试两次replace结果是不是我想要的:

echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g' abab 

那么我可以使用什么种子命令来replace如下?

 echo abbc | sed SED_COMMAND bcab 

编辑 :其实文本可能有超过2个模式,我不知道我需要多lessreplace。 由于有一个答案,说sed是一个stream编辑器,它的replace是贪婪的,我认为我将需要使用一些脚本语言。

也许这样的事情:

 sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g' 

~replace为你知道不会在string中的字符。

这可能适用于你(GNU sed):

 sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/;ta;s/\n(.)/\1\n/;ta' file 

这使用一个查找表,准备和保存在保持空间(HS),然后附加到每一行。 一个独特的标记(在这种情况下\n )被预置在该行的开头,并被用作在整个行的长度上search的方法。 一旦标记到达行末,过程结束,打印出来的查找表和标记被丢弃。

注意查找表是在开始时准备好的,并且select了第二个唯一的标记(在这种情况下),以免与replacestring冲突。

有一些意见:

 sed -r ' # initialize hold with :abbc:bcab 1 { x s/^/:abbc:bcab/ x } G # append hold to patt (after a \n) s/^/\n/ # prepend a \n :a /\n\n/ { P # print patt up to first \n d # delete patt & start next cycle } s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/ ta # goto a if sub occurred s/\n(.)/\1\n/ # move one char past the first \n ta # goto a if sub occurred ' 

表格是这样工作的:

  ** ** replacement :abbc:bcab ** ** pattern 

以下是对ooga答案的一个变体,它可以用于多个search和replace对,而不必检查值可能被重用的方式:

 sed -i ' s/\bAB\b/________BC________/g s/\bBC\b/________CD________/g s/________//g ' path_to_your_files/*.txt 

这里是一个例子:

之前:

 some text AB some more text "BC" and more text. 

后:

 some text BC some more text "CD" and more text. 

请注意, \b表示单词边界,这是防止________干扰search(我在Ubuntu上使用GNU sed 4.2.2)。 如果你不使用单词边界search,那么这种技术可能无法正常工作。

另外请注意,这与删除s/________//g并追加&& sed -i 's/________//g' path_to_your_files/*.txt到命令末尾的结果相同,但不需要指定path两次。

如果你知道你的文件中没有出现空值,就可以使用\x0_\x0_来代替________ , 正如jthill所build议的那样 。

sed是一个stream编辑器。 它贪婪地search和replace。 做你所要求的唯一方法是使用一个中间替代模式,并最终改变它。

echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'

Tcl有一个内置的这个

 $ tclsh % string map {ab bc bc ab} abbc bcab 

这是通过在string中一次一个字符地进行string比较而开始的。

在perl中:

 perl -E ' sub string_map { my ($str, %map) = @_; my $i = 0; while ($i < length $str) { KEYS: for my $key (keys %map) { if (substr($str, $i, length $key) eq $key) { substr($str, $i, length $key) = $map{$key}; $i += length($map{$key}) - 1; last KEYS; } } $i++; } return $str; } say string_map("abbc", "ab"=>"bc", "bc"=>"ab"); ' 
 bcab 

这是一个基于oogas sed

 echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1' bcab