我的GNU sed中向前查找正则表达式有什么问题?

75

这是我正在做的事情(简化示例):

gsed -i -E 's/^(?!foo)(.*)$/bar\1/' file.txt

我正在尝试在每行不以foo开头的行前面放置bar. 这是错误信息:

gsed: -e expression #1, char 22: Invalid preceding regular expression

有什么问题吗?


可能是 http://stackoverflow.com/questions/2086450/pcre-regex-to-sed-regex 的重复问题。 - hostmaster
1
这表明实际上可以使用sed实现相同的效果。 - erikbstack
我不同意。我正在寻找如何在sed中进行前瞻的方法,而对于这个问题的答案是:你不能。 - Cecile
3个回答

175
sed -i '/^foo/! s/^/bar/' file.txt
  • -i 意为原地修改文件
  • /^foo/! 只对不以 foo 开头的行进行下一步操作
  • s/^/bar/ 将行首替换为 bar。

8
非常好的解决方案。无需回溯。只需使用sed已有的功能即可。 - D.Shawley
13
对于像 ^foo 这样的锚定表达式来说,这是可行的,但不幸的是并不能扩展到模式中任何位置的负向先行断言。 - tripleee
3
然而,当行中只存在一个替换实例时,它会进行扩展。例如,'s/(?!foo)baz/bar/' => '/foobaz/! s/baz/bar/'。也许巧妙地应用这种方法可以扩展到包含“foobaz baz”等内容的行。 - Nathan Vance
你,先生,是我的英雄。完美的解决方案。非常感谢。 - devDomm
1
@Nabheet:我不确定您想要删除哪些行。您的代码说“搜索不包含foo的行”,然后,没有给出命令,说明要对这些行执行什么操作,而是给出了另一个过滤器。这是行不通的。如果您想要删除所有不包含foo的行,则使用“/foo/! d”如果您想要删除所有不包含foo但包含bar的行,则需要在第一个过滤器之后使用块命令来应用第二个过滤器:“/foo/! {/bar/d}”请注意,原始问题是关于以foo开头的行,您通过删除^来删除了它。 - kkeller
显示剩余5条评论

74
据我所知,sed既没有向前查找也没有向后查找。建议转用更加强大、语法类似的编程语言,例如perl

31
一个简单的 sed 转换成 perl 的参考代码:sed 's/before/after/g' /my/file => cat /my/file | perl -ne 's/before/after/g; print;' - Batandwa
25
使用cat和管道符将内容输入perl是多余的。只需使用perl -pi -e 's/before/after/g' /my/file即可。 - ypid
3
很不幸,没有前瞻性。 - NelsonGon
3
我认为这个回答是错误的:sed有提供多个编辑序列的能力,就像kkeller的回答所说。 - Cirelli94
@Cirelli94:虽然这是一个不错的建议,但这并不是正则表达式语法中的负向先行断言。 - v01pe

11

您使用的是Perl兼容正则表达式(PCRE)语法,而GNU sed不支持这种语法。您应该按照SED 正则表达式的规则重写您的正则表达式或改用perl

请注意,SED没有前瞻,并且因此不支持您尝试使用的正则表达式特性。可以使用其他功能在SED中完成,就像其他人已经提到的那样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接