如何在git配置别名内的bash片段内的命令替换中使用括号字符?

时间:2015-08-05 08:23:29

标签: git bash

以下是我正在编辑的配置的摘录。这位于[alias]的{​​{1}}部分:

.gitconfig

我基本上试图将ignored = !git ls-files -v | grep "^S" status-with-ignored = "!f() { git status; ignored=$(git ignored | cut -d ' ' -f 2 | sed -e s/^/z/ -e s/$/z/); [ -n \"$ignored\" ] && echo \"git skip-worktree (ignored):\n$ignored\"; };f" 的输出着色,因为我将它粘贴到git状态的末尾。我上面显示的工作正常,但如果我的git ignored命令里面有任何括号(对于构建正则表达式非常有用),它不起作用(fatal: bad config file line 18 in ~/.gitconfig)。

例如,我希望能够编写具有parens的内容,例如sed而不是sed s/^(.*)$/z\1z/

由于我会使用sed -e s/^/z/ -e s/$/z/\x1b[31m等来实现颜色化,但您明白了这一点。

我尝试过一个,两个,三个和四个反斜杠以逃避这些问题,但没有任何效果。

1 个答案:

答案 0 :(得分:3)

这里有一些单独的问题:一个是你的配置转义,一个是sed中的括号,另一个是git别名中的<(date)进程替换。

配置转义

首先,bad config file的问题不是命令替换,而是你的换行符。

[YOURS] status-with-ignored = "!f() { git status; ignored=$(git ignored | cut -d ' ' -f 2 | sed -e s/^/z/ -e s/$/z/); [ -n \"$ignored\" ] && echo \"git skip-worktree (ignored):\n$ignored\"; };f"
 [MINE] status-with-ignored = "!f() { git status; ignored=$(git ignored | cut -d ' ' -f 2 | sed -e s/^/z/ -e s/$/z/); [ -n \"$ignored\" ] && echo \"git skip-worktree (ignored):\\n$ignored\"; };f"

您的\n似乎被解释为应用于配置文件;这是需要逃避的部分,而不是任何与人有关的事情。

我通过让bashgit config为我处理转义,然后用cut " "代替' '来获得上述内容:

git config alias.status-with-ignored '!f() { git status; ignored=$(git ignored | cut -d " " -f 2 | sed -e s/^/z/ -e s/$/z/); [ -n "$ignored" ] && echo "git skip-worktree (ignored):\n$ignored"; };f'

(如果你想聪明一点escaping single quotes within bash single quotes,你可以,但对我来说,它可以有效地防止可读性。)

sed中的括号

其次,Bash和其他shell无法处理未加引号的括号。这不是git别名特有的,这只是解析规则。

echo I am (Batman)    # Doesn't work
echo I am Batman      # Does work

后者有效;蝙蝠侠没有parens。

您可以转义括号或引用字符串:

echo "I am (Batman)"  # Works
echo I am \(Batman\)  # Also works

将您的配置文件保留为:

status-with-ignored = "!f() { git status; ignored=$(git ignored | cut -d ' ' -f 2 | sed -e \"s/^(.*)$/z\1z/\"); [ -n \"$ignored\" ] && echo \"git skip-worktree (ignored):\\n$ignored\"; };f"

或者你的git config语句如下:

git config alias.status-with-ignored '!f() { git status; ignored=$(git ignored | cut -d " " -f 2 | sed -e "s/^(.*)$/z\1z/"); [ -n "$ignored" ] && echo "git skip-worktree (ignored):\n$ignored"; };

git中的进程替换

最后,似乎git alias只是不处理进程替换。来自the git config man page

  

参数按空格分隔,支持通常的shell引用和转义。引号对或反斜杠可用于引用它们。

看起来git正在使用sh或它自己的解析,而不是调用bash本身,因为本地不支持non-portable bash extension进程替换。你可以抨击bash:

git config alias.sample '!cat <(seq 3)'; git sample
git config alias.sample '!bash -c "cat <(seq 3)"'; git sample

...但此时您可能只是make a script named git-status-with-ignored and add it to your path