为什么备用分隔符不能与sed-e'/模式/s/a/b/';?

为什么备用分隔符不能与sed-e'/模式/s/a/b/';?,sed,perl,Sed,Perl,我发现了一些没有意义的东西 cat config.h的输出: define somevar foo // Sample variable 此版本的命令用于将foo更改为bar并保留注释: sed -e '/somevar/s/foo/bar/' config.h 这不起作用: sed -e '|somevar|s|foo|bar|' config.h 给出此错误: sed:-e表达式#1,字符1:未知命令:` |' 有趣的是,这确实有效: sed -e '/somevar/s|foo|ba

我发现了一些没有意义的东西

cat config.h的输出

define somevar foo // Sample variable
此版本的命令用于将foo更改为bar并保留注释:

sed -e '/somevar/s/foo/bar/' config.h
这不起作用:

sed -e '|somevar|s|foo|bar|' config.h
给出此错误:

sed:-e表达式#1,字符1:未知命令:` |'

有趣的是,这确实有效:

sed -e '/somevar/s|foo|bar|' config.h
也许我遗漏了一些文档。在同一个sed命令中使用两个不同的分隔符似乎很奇怪

Bug还是功能?

我投票支持功能

它们是两个不同的命令,搜索命令和替换命令。据我所知,它只允许更改替换命令的分隔符

中国的情况也类似。可以使用
/…/
执行正则表达式搜索,但如果要更改分隔符,则必须使用
m
将其明确标记为搜索,如:
m |…|


我想这可能与一些词法分析问题有关,但我不知道原因。

允许对
/pattern/
使用不同的分隔符会导致分析歧义

ispaghetti
应该像
/spaghett/
那样,还是应该像
i spaghetti
那样插入文本

对于
s
y
不存在这种歧义。当您看到这两个字符中的任何一个时,您就知道正在读取的命令,然后可以将下一个字符解释为分隔符

如果我们用一个类似的可识别字符开始它,我们可以解决
/pattern/
的这种歧义,而且sed确实有一个单独的地址说明符:反斜杠,如
\\\\pattern
(这与转义不同)

因此,我们可以编写
\\pattern | s | foo | bar

地址和编辑命令是分开的,因此
\$pattern$s\u foo\u bar
/pattern/s\foo\u bar
也可以工作

这将起作用:

sed -e '\|somevar|s|foo|bar|'
GNU sed的
man
页面非常清楚这一点:

   /regexp/
          Match lines matching the regular expression regexp.

   \cregexpc
          Match lines matching the regular expression regexp.  The  c  may
          be any character.
也就是说,
c
可以是任何字符,但开头的
\
是必需的

我周围没有免费的BSD,但根据
man
页面,也有非常清楚的:

除非是斜杠,否则开头分隔符前面必须加反斜杠

另一方面,在OSX中,这一点根本不清楚:

      In a context address, any character other than a backslash (``\'')
      or newline character may be used to delimit the regular expression.
      Also, putting a backslash character before the delimiting character
      causes the character to be treated literally.  For example, in the
      context address \xabc\xdefx, the RE delimiter is an ``x'' and the
      second ``x'' stands for itself, so that the regular expression is
      ``abcxdef''.
请注意,这里的示例使用了
\xpatternx
,而不仅仅是
xpatternx
。这就是它给出的所有线索,它没有明确说明
xpatternx
将不起作用


根据的论点,
sed
(以及前面提到的其他语言,如
perl
)需要这个额外的线索才能正常工作。您完全可以对匹配的地址使用备用分隔符(
/regex/
),但是您需要告诉sed,您打算使用该分隔符进行匹配。执行此操作的方法是使用前导反斜杠
\
。因此,您的命令可以是:

sed -e '\|somevar|s|foo|bar|' config.h
或者同样容易:

sed -e '\%somevar%s|foo|bar|' config.h
参考:功能。在

 sed -e '/somevar/s/foo/bar/' config.h
/somevar/
是一个地址。地址必须与其他功能区分开来,如
y
(yank)、
i
(insert)、
a
(append)等。通常,sed命令被解析为

 [address[,address]]function[arguments]

你说得对,但是sed在这种情况下使用“\”而不是
m
。@bonsaiviking:我不知道。我会在这里感谢你,并将投票表决你的答案,澄清它。它在,而且FreeBSD的手册页更清楚:“除非是斜杠,否则开头分隔符前面必须有反斜杠。”谢谢@bonsaiviking,我可以在Linux上检查它更清楚。我改进了我的答案。很好地讨论了解析歧义,但是如果第一个分隔符前面有反斜杠“\”@bonsaiviking,sed确实提供了这个功能,这是一个很好的观点。