我正在尝试使用sed,最近我注意到了有趣的行为。但是,我找不到任何描述它的文档。
想象一下,我们有一个名为'sedtest'的文件:
$cat sedtest
hello 0 world
example
4 sed
Phone number: 123-456-789
接下来,我将通过sed:
运行它$cat sedtest | sed '/\([[:digit:]]\+\)/s,,(\1),'
hello (0) world
example
(4) sed
Phone number: (123)-456-789
这很容易理解sed脚本:
\([[:digit:]]\+\)
,这意味着“匹配包含1位或更多位数的字符串”。请注意,我还使用s
- 命令式\(
和\)
括号来标记子字符串(是否允许?)。s
命令s,,(\1),
(带有空的正则表达式字段),这意味着“将匹配的子字符串替换为(\1)
”。最初我认为它应该失败并出现错误,因为\1
和类似的反向引用应仅适用于来自s
命令匹配器字段的子字符串,在这种情况下为空。
但结果就好像是s,\([[:digit:]]\+\),(\1),
脚本(\regexp\
匹配器在s
命令匹配器字段内移动了一样!)
所以,问题是:从\regexp\
命令s//replace/
规则反对引用文本的子字符串是否正常(即所需行为),好像它们被s/regexp/replace/
匹配一样命令?
P.S。
我的sed版本是:GNU sed 4.2.1
问题背后的动机就是你可以做的事情:
sed '/^Number: \([[:digit:]]\+\)$/{s,,#NUMBER: (\1),;p;d};q 1'
,即
/^Number: \([[:digit:]]\+\)$/
- 匹配每个字符串Number: 12345
,如果匹配,则:
s,,#NUMBER: (\1),
- 将其替换为#NUMBER: (12345)
p
- 打印d
- 清除模式空间,启动新周期(获取新行并从头开始解析脚本表达式)q 1
- 退出代码1.此命令仅在步骤1中未发生匹配时执行(因为d
命令存在) - 它检查“不匹配”的情况,这在我的情况意味着'不允许使用字符串'并且必须导致错误。这里的主要技巧是在替换发生后执行p
和d
命令,这在使用'normal's/match/replace/
命令时是不可能的。
答案 0 :(得分:1)
这很正常。除非您执行其他匹配,否则后引用保留空间不会被清除。由于s
的正则表达式为空,\1
指的是之前的捕获组。你可以看到差异:
$ sed '/\([[:digit:]]\+\)/s,\(a\),(\1),' sedtest
hello 0 world
example
4 sed
Phone number: 123-456-789
没有匹配(带有数字的行也有a
,但后面的引用保持已被清除
$sed '/\([[:digit:]]\+\)/s,\(e\),(\1),'
h(e)llo 0 world
example
4 s(e)d
Phon(e) number: 123-456-789
e
匹配,后者成为后方参考。
如果您不想要这种行为,则不应该首先在\( \)
附近放置[[:digit:]]
来创建后退引用。