status="status && foo=bar"
,但是当我尝试这样做并执行 echo $foo
时,没有输出“bar”。然而,如果我手动输入 git status && foo=baz
,然后执行 echo $foo
,输出是“baz”。为什么我不能在别名中声明变量?我注意到,如果我改变顺序并执行
alias git="foo=bar && git"
,然后尝试任何 git 命令并执行echo foo
,它的值是“bar”。status="status && foo=bar"
,但是当我尝试这样做并执行 echo $foo
时,没有输出“bar”。然而,如果我手动输入 git status && foo=baz
,然后执行 echo $foo
,输出是“baz”。为什么我不能在别名中声明变量?alias git="foo=bar && git"
,然后尝试任何 git 命令并执行echo foo
,它的值是“bar”。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始终有它们。
# test.sh:
#!/bin/bash
foo=bar
echo "from script: $foo"
$ ./test.sh && echo "from cli: $foo"
from script: bar
from cli:
foo=bar
在该环境中被定义,并在进程退出后被丢弃。
$ mytest () {
foo=bar
echo "from function: $foo"
}
$ mytest && echo "from cli: $foo"
from function: bar
from cli: bar
git别名将始终作为单独的进程执行,如果您想设置一个“超出”调用的环境变量,您将不得不使用其他构造。
例如,您可以在.bashrc
中定义一个函数:
mystatus () {
git status && foo=bar
}
之后,您将能够从任何启动的shell中调用mystatus
。
如果命令如此简单,那么它实际上相当于一个bash别名,好处是如果需要扩展该函数的内容,将更容易实现。