问题描述
我在理解如何使用grep来完成一个看似简单的任务时遇到了一些麻烦。我想匹配出现在许多文件中的子字符串,但我想忽略该子字符串以字母或数字开头的情况
{ some word: ['bar-something','bar-somthing-else'] },{ some text: ['bar-fab','bar-fab-foo','bar-eggs'] },<bar-sometext>Hello World!</bar-sometext>
'bar-foobar-foo'
'bar-foo'
我想替换所有的ket-外观,但是仅在bar前面没有字母或数字的情况下
'bar-foobar-foo'
应更改为
'ket-foobar-foo'
但是我遇到了一些麻烦,因为grep命令与他们自己的规则不一致
让我解释一下:
命令:
git grep -l 'bar-' | xargs sed -i '' -e 's/bar-/ket-/g'
几乎可以工作,唯一的问题是它也改变了以字母或数字开头的条形:
'bar-foobar-foo'
至'ket-fooket-foo'
要进行一些测试,在进行替换之前,我仅与grep匹配。我期待该命令
grep -E '[^a-zA-Z0-9]ket-' a.file
很有用,但它也匹配单词ket-之前的任何特殊字符。例如,匹配
<bar-
'bar-
\bar-
(为简单起见,我删除了其余文本,上面突出显示为匹配的文本),而不是仅匹配bar-。为什么这样做?当我不排除字母或数字时,grep与前面的特殊字符不匹配。
我怎么能只替换bar-而不匹配其他任何内容,但是同时忽略了该子字符串前面带有任何字母或数字的任何情况。我给出的示例的预期输出是:
{ some word: ['ket-something','ket-somthing-else'] },{ some text: ['ket-fab','ket-fab-foo','ket-eggs'] },<ket-sometext>Hello World!</ket-sometext>
'ket-foobar-foo'
'ket-foo'
顺便说一句,我使用的是Mac,遇到替换命令时遇到的麻烦
git grep -l 'bar-' | xargs sed -i '' -e 's/bar-/ket-/g'
在我的带有oh-my-zsh终端的Mac上运行良好,我将不胜感激任何看起来像上面命令的答案
预先感谢
解决方法
也许,您应该使用另一种支持后向断言的工具。
perl -pi.bak -e 's/(?<![\p{L}\d])bar/test/g' file.txt
-
-p
处理,然后逐行打印<>
, -
-i
激活就地编辑。file.txt
将以.bak
扩展名进行备份, -
-e
表示第一个参数是Perl单行代码,而不是Perl可执行文件, -
(?<!
是断言背后的断言, -
\p{L}
是任何字母。
受https://stackoverflow.com/a/6995010/6632736的启发。
,使用GNU sed:
sed 's/\([^[:alnum:]]\)bar/\1ket/g' file
这是's/pattern/replace/g'
形式的sed替换,其中g
表示全局。
匹配模式表示:一个非字母数字字符,后跟“ bar”。替换字符是匹配的字符(\1
,后跟ket
。无论嵌套在匹配模式中括号之间的内容如何,都可以重复使用,例如\1
\2
等,直到\9
。
您可以就地执行此操作,就像在示例命令中一样(以及任何特定于macOS的调整)。另外,grep
并不用于替换,它仅提取文本,通常没有理由将其与awk或sed一起使用。