Sed:'s'命令中来自行匹配regexp的反向引用子串

时间:2014-04-16 18:59:17

标签: sed

我正在尝试使用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脚本:

  1. 首先,它匹配字符串regexp \([[:digit:]]\+\),这意味着“匹配包含1位或更多位数的字符串”。请注意,我还使用s - 命令式\(\)括号来标记子字符串(是否允许?)。
  2. 如果匹配,则继续使用s命令s,,(\1),(带有空的正则表达式字段),这意味着“将匹配的子字符串替换为(\1)”。
  3. 最初我认为它应该失败并出现错误,因为\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',即

    1. /^Number: \([[:digit:]]\+\)$/ - 匹配每个字符串Number: 12345,如果匹配,则:
      • s,,#NUMBER: (\1), - 将其替换为#NUMBER: (12345)
      • p - 打印
      • d - 清除模式空间,启动新周期(获取新行并从头开始解析脚本表达式)
    2. q 1 - 退出代码1.此命令仅在步骤1中未发生匹配时执行(因为d命令存在) - 它检查“不匹配”的情况,这在我的情况意味着'不允许使用字符串'并且必须导致错误。
    3. 这里的主要技巧是在替换发生后执行pd命令,这在使用'normal's/match/replace/命令时是不可能的。

1 个答案:

答案 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:]]来创建后退引用。