如何用sed一次替换多个模式?

Dan*_*oNC 190 syntax replace sed

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

  • ab - > bc
  • bc - > ab

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

echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g'
abab
Run Code Online (Sandbox Code Playgroud)

那么我可以使用什么sed命令替换如下?

echo abbc | sed SED_COMMAND
bcab
Run Code Online (Sandbox Code Playgroud)

编辑:实际上文本可能有两个以上的模式,我不知道我需要多少替换.既然有一个答案说这sed是一个流编辑器并且它的替换是贪婪的,我认为我需要使用一些脚本语言.

oog*_*oga 288

也许是这样的:

sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'
Run Code Online (Sandbox Code Playgroud)

替换~为您知道不会在字符串中的字符.

  • @Lee`g`用于全局 - 它替换每行中模式的所有实例,而不是仅替换第一行(这是默认行为). (10认同)
  • _你知道不会出现在字符串中_对于生产代码,不要对输入做任何假设。对于测试来说,测试永远不会真正证明正确性,但是测试的一个好主意是:使用脚本本身作为输入。 (7认同)
  • GNU sed处理nuls,所以你可以使用`\ x0`来表示`~~`. (6认同)
  • g是必须的吗?它有什么作用? (2认同)
  • 请参阅我的答案 http://stackoverflow.com/a/41273117/539149,了解 ooga 答案的变体,可以同时替换多个组合。 (2认同)

Pau*_*ves 22

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

$ sed -e 's:AND:\n&:g' -e 's:GROUP BY:\n&:g' -e 's:UNION:\n&:g' -e 's:FROM:\n&:g' file > readable.sql

这将在所有AND,GROUP BY,UNION和FROM之前附加'\n',而'&'表示匹配的字符串,'\n&'表示您希望在'匹配之前用'\n'替换匹配的字符串"

  • 它返回`sed:-e:没有这样的文件或目录` (2认同)
  • 如果我使用“sed -i -e”怎么办? (2认同)

Zac*_*ris 12

以下是ooga答案的变体,适用于多个搜索和替换对,而无需检查如何重用值:

sed -i '
s/\bAB\b/________BC________/g
s/\bBC\b/________CD________/g
s/________//g
' path_to_your_files/*.txt
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

之前:

some text AB some more text "BC" and more text.
Run Code Online (Sandbox Code Playgroud)

后:

some text BC some more text "CD" and more text.
Run Code Online (Sandbox Code Playgroud)

注意,\b表示单词边界,这是防止________干扰搜索的原因(我在Ubuntu上使用GNU sed 4.2.2).如果您没有使用单词边界搜索,则此技术可能无效.

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

如果您知道文件中没有空值,则使用\x0_\x0_代替________,如jthill建议的那样.


kur*_*der 8

sed是流编辑器。它搜索并替换贪婪。完成您所要求的唯一方法是使用中间替换模式并将其最终更改回去。

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


Дід*_*lik 8

以下是SED 手册的摘录:

-e 脚本

--表达式=脚本

将脚本中的命令添加到处理输入时要运行的命令集中。

在每个替换前面加上-e选项并将它们收集在一起。对我有用的示例如下:

sed < ../.env-turret.dist \
  -e "s/{{ name }}/turret$TURRETS_COUNT_INIT/g" \
  -e "s/{{ account }}/$CFW_ACCOUNT_ID/g" > ./.env.dist
Run Code Online (Sandbox Code Playgroud)

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


pot*_*ong 5

这可能对你有用(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
Run Code Online (Sandbox Code Playgroud)

这使用了一个查找表,该表准备并保存在保持空间 (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
'
Run Code Online (Sandbox Code Playgroud)

该表的工作方式如下:

   **   **   replacement
:abbc:bcab
 **   **     pattern
Run Code Online (Sandbox Code Playgroud)