在Git别名中设置环境变量

3
如果我想在每次使用 git status 命令时都将 foo 的值设置为“bar”,该怎么做呢?我的第一个想法是为 status 设置一个别名,即 status="status && foo=bar",但是当我尝试这样做并执行 echo $foo 时,没有输出“bar”。然而,如果我手动输入 git status && foo=baz,然后执行 echo $foo,输出是“baz”。为什么我不能在别名中声明变量?
我注意到,如果我改变顺序并执行alias git="foo=bar && git",然后尝试任何 git 命令并执行echo foo,它的值是“bar”。
2个回答

7

Git别名会被以下方式运行:

  • 如果别名不以!开头,则由Git本身运行:在这种情况下,您无法设置新的环境变量;或
  • 如果别名以!开头,则由符合POSIX标准的shell运行。

符合POSIX标准的shell有两种设置环境变量的方法:

VAR=value command

或者:
VAR=value; export VAR; command1; command2; ...; commandN

这个第二种变体可以写成:

export VAR=value; command1; ...; commandN

明确导出的变量对于以这种方式调用的所有命令都是设置的,与VAR=value command不同,后者仅为一个命令设置该变量,因为此设置是在shell中完成的,并持续到shell本身退出,然后随着已退出的shell一起消失。所以如果x是Git别名:
git x

通过设置一个别名(alias),可以针对所运行的命令在环境变量中进行一次性的设定。之后,运行这些命令的 shell 退出,所有的设置都会消失。

因此,Git 别名无法在你用于运行该别名的命令行 shell 中设置任何环境变量。这适用于所有命令,而不仅仅是 Git 命令:没有任何命令能够在任何“外部”的 shell 中设置环境变量。

但有一个逃生口,就是当你自己编写一个 shell 命令时,你拥有控制权。例如,你可以编写一个相当愚蠢的 shell 命令:

export VAR=$(echo value)

括号内的$(echo value)会被计算并替换为其输出。但这意味着,如果某个程序打印了一些你想要保存的值,你可以写:

var=$(command)

它将本地shell变量var设置为输出内容,或者:

export VAR=$(command)

该命令设置并导出shell变量。(注意:这里的大写仅是约定俗成的,被导出的本地shell变量通常用全大写表示,而未导出的本地shell变量通常用全小写表示。)

还有第二个逃生口,但使用它很危险:POSIX shell具有一个 eval 命令,可将文本传递回shell解释器。我们可以将其与输出“export VAR1=value1; export VAR2=value2”的程序一起使用:

eval `ssh-agent -s`

这里,ssh-agent 程序设置代理并打印多个适当的 export 命令。然而,如果 ssh-agent 程序打印 rm -rf /,使用 eval ssh-agent -s 将会继续删除它可以访问到的所有文件:这意味着你正在对那个 ssh-agent 命令中放置了大量的信任。

您可以使用一个 shell 别名来创建一些易于输入的命令,例如 gst,由变量设置操作和 Git 命令组成:

alias gst='foo=bar && git status'

这不是一个 Git 别名。这是一个 shell 别名。现在POSIX要求使用shell别名(感谢 KamilCuk 的指引)。 虽然一些非 Bash shell 可能没有它们,但Bash始终有它们。


很棒的回答!“并非所有兼容POSIX的shell都具有shell别名。” 哎呀,如此吹毛求疵:有趣的事实是:别名是posix的一部分 https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_03_01 ,因此一个兼容posix的shell必须具有别名。不知道,在早期的posix中是否存在别名。 - KamilCuk
@KamilCuk:有趣。许多旧系统上的旧/bin/sh没有别名。不过我会更新答案的。 - torek

1
关于您的shell行为:
如果您编写以下脚本:
# test.sh:
#!/bin/bash

foo=bar
echo "from script: $foo"

当你运行它时,你会看到以下内容:
$ ./test.sh && echo "from cli: $foo"
from script: bar
from cli: 

运行脚本会创建一个全新的进程,并有自己的环境变量,foo=bar在该环境中被定义,并在进程退出后被丢弃。
要在当前 shell 中定义该变量,您需要使用其他方法。
@torek 提到:
- 使用脚本输出调用 eval ... - 创建一个 shell 别名
我还要补充:
- 调用函数而不是脚本:
$ mytest () {
   foo=bar
   echo "from function: $foo"
}

$ mytest && echo "from cli: $foo"
from function: bar
from cli: bar

  • 关于git别名:

git别名将始终作为单独的进程执行,如果您想设置一个“超出”调用的环境变量,您将不得不使用其他构造。

例如,您可以在.bashrc中定义一个函数:

mystatus () {
    git status && foo=bar
}

之后,您将能够从任何启动的shell中调用mystatus

如果命令如此简单,那么它实际上相当于一个bash别名,好处是如果需要扩展该函数的内容,将更容易实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接