Git filter 和 sed 争夺 `\$`

Git filter and sed fight over `\$`

我正在尝试使用 sed

编写 git 过滤器
[filter "revisioner"]
        smudge = sed -e "s/\$Revision\$/$Revision: $(GIT_EXEC_PATH=/usr/lib/git-core/ git describe --tag svn)$/g"
        clean = sed -e "s/\$Revision: [^$]*\$/$Revision$/g"

为了 sed 做正确的事情,它需要奇数个 \ 来逃避 $,但是 git 抱怨奇数个\ 与:

fatal: bad config line 2 in file .git/../.gitconfig

我真的不想将我的 sed 脚本移动到外部命令中,因为它是我的用户在使用我的存储库之前需要在他们的系统上设置的另一个移动部分。

有什么建议吗?

sed 不需要奇数 个反斜杠。 sed 需要 从任何调用 sed 的地方接收 ,two-character 序列反斜杠,dollar-sign.

Git 本身将两个反斜杠变成一个反斜杠。

Git 调用 运行 命令的 shell 也会将两个反斜杠变成一个反斜杠,只要它在词法上扫描不包含在单引号内的文本。

因此,如果您以 四个 反斜杠开头:

\\$

Git 会将每对变成 两个 反斜杠:

\$

然后 shell 会将一对反斜杠变成一个反斜杠:

$

之后 sed 将看到一个反斜杠后跟一个美元符号。

请注意,您必须在解释反斜杠的每个点执行此加倍操作。如果应用了更多级别的解释,则需要 8 个 反斜杠。这种事情很快就会变得丑陋,这就是为什么人们将它们移到其他脚本中的原因。如果您将脚本作为存储库中的已提交文件提供,那么处理起来可能会容易得多...

正确进行转义解析通常是一个挑战,因为您必须考虑将解析命令的每个程序,并且必须按顺序考虑它们。

torek 的回答概述了适用于您的案例的基本推理。我将添加以下内容,因为我认为最终结果更具可读性:

首先,让底层的 sed 脚本在命令行工作——在我的测试中,将 $HI$ 转换为 $Hello, World$——我使用了

sed -e 's/$HI$/$Hello World$/g'

single-quotes 防止 bash 混淆转义,因此 sed 看到 $ 并匹配文字 $。请注意,输出模式不需要这种转义。

然后将其放入 .git/config 文件中,将每个反斜杠加倍,得到

clean = sed -e 's/\$HI\$/$Hello World$/g'

这在我的测试中有效;如果它对您不起作用,我们可能需要更多信息来了解发生了什么。