假设我有'abbc'字符串,我想替换:

Ab -> BC BC -> ab

如果我尝试两次替换,结果不是我想要的:

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

那么我可以像下面这样使用什么sed命令来替换?

echo abbc | sed SED_COMMAND
bcab

编辑: 实际上,文本可以有超过2个模式,我不知道我需要多少替换。因为有一个答案说sed是一个流编辑器,它的替换是贪婪的,我认为我将需要使用一些脚本语言。


当前回答

这可能为你工作(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)被前置在行开始之前,并用作在整个行长度上进行搜索的方法。一旦标记到达行尾,该过程就完成了,并打印出查找表,标记被丢弃。

注意:查找表在一开始就准备好了,并且选择了第二个唯一标记(在本例中为:),以避免与替换字符串冲突。

以下是一些评论:

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

其他回答

我相信这应该能解决你的问题。我可能遗漏了一些边缘情况,如果你注意到一个,请评论。

您需要一种方法将以前的替换从未来的模式中排除,这实际上意味着使输出可区分,并将这些输出从搜索中排除,最终使输出再次不可区分。这与引用/转义过程非常相似,因此我将从中吸取教训。

S /\\/\\\\/g转义所有现有的反斜杠 S /ab/\\b\ c/g用原始ab代替已转义的BC S /bc/\\a\ b/g将原始bc替换为转义的ab s/\\\(.\)/\1/g将所有转义的X替换为原始X

我没有解释ab或bc中的反斜杠,但直觉上,我将以同样的方式转义搜索和替换术语——\ now匹配\\,而被替换的\\将显示为\。

到目前为止,我一直使用反斜杠作为转义字符,但它不一定是最好的选择。几乎任何字符都可以工作,但是要注意环境中需要转义的字符,sed等,这取决于您打算如何使用结果。

以下是SED手册的节选:

- e脚本 ——表达=脚本 将脚本中的命令添加到处理输入时要运行的命令集中。

在每个替换前加上-e选项并将它们收集在一起。下面是一个适合我的例子:

sed < ../.env-turret.dist \
  -e "s/{{ name }}/turret$TURRETS_COUNT_INIT/g" \
  -e "s/{{ account }}/$CFW_ACCOUNT_ID/g" > ./.env.dist

这个例子还展示了如何在替换中使用环境变量。

这是一个基于oogas sed的awk

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

也许是这样的:

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

将~替换为一个您知道不会出现在字符串中的字符。

我总是使用多个带有"-e"的语句

$ sed - e ' s:和:\ n: g - e ' s GROUP BY: \ n: g - e ' s:联盟:\ n: g - e ' s:从:\ n: g的文件> readable.sql

这将在所有AND, GROUP BY, UNION和FROM之前添加一个'\n',而'&'表示匹配的字符串,'\n&'表示您想在'matched'之前用'\n'替换匹配的字符串。