sed 从字面上匹配“$”而不考虑它的正则表达式

Moh*_*rmi 1 regex linux bash shell sed

我试图在 sed -e 命令中使用 $ 并且它有效,例如:

sed -e 's/world$/test/g' test.txt
Run Code Online (Sandbox Code Playgroud)

上面的命令将替换字符串末尾的“world”。

令我困惑的是,以下内容确实有效:

sed -e 's/${projects.version}/20.0/g' test.txt
Run Code Online (Sandbox Code Playgroud)

上面的命令替换了${projects.version},我没有任何解释 sed 是如何匹配的$并且没想到它是一个特殊字符?

Ed *_*ton 5

正如POSIX 规范所说:

$ <dollar-sign> 在用作锚点时应该是特殊的。

当用作整个 BRE 的最后一个字符时, <dollar-sign> ( '$' ) 应为锚点。当用作子表达式的最后一个字符时,实现可以将 <dollar-sign> 视为锚点。<dollar-sign> 应将表达式(或可选的子表达式)锚定到所匹配字符串的末尾;<dollar-sign> 可以说是匹配最后一个字符后面的字符串结尾。

因此,当它不在 BRE 末尾时,它只是一个文字$字符。

对于 ERE,第二段有点不同:

括号表达式外部的 <dollar-sign> ( '$' ) 应将其结束的表达式或子表达式锚定到字符串的末尾;这样的表达式或子表达式只能匹配以字符串的最后一个字符结尾的序列。例如,ERE“ef$”和“(ef$)”匹配字符串“abcdef”中的“ef”,但在字符串“cdefab”中匹配失败,并且ERE“e$f”有效,但是永远无法匹配,因为“f”阻止表达式“e$”匹配以最后一个字符结尾的内容。

请注意最后一句 - 这意味着$当不在正则表达式末尾时,在 ERE 中不会按字面意思进行处理,它只是无法匹配任何内容。

不过,这是您永远不必担心的事情,因为为了清楚起见,如果没有其他事情,您应该始终确保编写正则表达式以转义您想要按字面处理的任何正则表达式元字符,因此您不应该编写:

's/$foo/bar/'
Run Code Online (Sandbox Code Playgroud)

但改为写以下其中一个:

's/\$foo/bar/'
's/[$]foo/bar/'
Run Code Online (Sandbox Code Playgroud)

那么上面提到的语义都不重要了。

$在这种情况下,BRE 与 ERE 处理方式之间差异的基本原理在https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap09.html#tag_21_09_03_08进行了解释,但基本上只是标准是以这种方式编写是为了适应人们在 BRE 与 ERE 中使用的方式的不同历史行为$

感谢SO 上的@M.NejatAydin和 usenet 上 comp.unix.shell 中的@oguzismail帮助澄清了基本原理。