Emi*_*rey 9 git bash shell alias exit
如果我没有明确地调用exit某些基于函数的Bash脚本,那么对于某些函数还会有其他意外的执行.是什么造成的?在将一个git别名作为回答StackOverflow上另一个用户问题的一部分时,首先注意到了这种行为.该别名由此脚本组成(该函数运行两次而不是一次):
#!/usr/bin/env bash
github(){
echo github;
};
twitter(){
echo twitter;
};
facebook(){
echo facebook;
};
if [[ $(type -t "$1") == "function" ]];
then
"$1";
else
echo "There is no defined function for $1";
fi;
Run Code Online (Sandbox Code Playgroud)
但是这个略微修改的脚本按预期执行(仅运行一次函数):
#!/usr/bin/env bash
github(){
echo github;
};
twitter(){
echo twitter;
};
facebook(){
echo facebook;
};
if [[ $(type -t "$1") == "function" ]];
then
"$1";
exit 0;
else
echo "There is no defined function for $1";
exit 1;
fi;
Run Code Online (Sandbox Code Playgroud)
这正是我通过git别名运行这些脚本时所发生的事情(添加的set命令仅用于调试目的):
$ git config --global alias.encrypt-for '!set -evu -o pipefail;github(){ echo github;};twitter(){ echo twitter;};facebook(){ echo facebook;};if [[ $(type -t "$1") == "function" ]];then "$1"; exit 0; else echo "There is no defined function for $1"; exit 1; fi;'
$ git encrypt-for "github"
type -t "$1"
github
$ git config --global alias.encrypt-for '!set -evu -o pipefail;github(){ echo github;};twitter(){ echo twitter;};facebook(){ echo facebook;};if [[ $(type -t "$1") == "function" ]];then "$1"; else echo "There is no defined function for $1"; fi;'
$ git encrypt-for "github"
type -t "$1"
github
github
Run Code Online (Sandbox Code Playgroud)
输出来自set -x:
$ git encrypt-for "github"
++ type -t github
+ [[ function == \f\u\n\c\t\i\o\n ]]
+ github
+ echo github
github
+ github
+ echo github
github
Run Code Online (Sandbox Code Playgroud)
从替换输出echo github与echo "I am echo in github"作为排除了的一种方式echo命令作为所述第二功能执行的源代码:
$ git encrypt-for "github"
++ type -t github
+ [[ function == \f\u\n\c\t\i\o\n ]]
+ github
+ echo 'I am echo in github'
I am echo in github
+ github
+ echo 'I am echo in github'
I am echo in github
Run Code Online (Sandbox Code Playgroud)
以下是别名/脚本的最简单版本,它提供了双重执行的不良行为:
g(){
echo "once";
};
$1;
Run Code Online (Sandbox Code Playgroud)
这是执行简化别名/脚本(具有执行两次的错误行为)的结果输出:
$ git config --global alias.encrypt-for '!g(){ echo "once";};$1;'
$ git encrypt-for g
once
once
Run Code Online (Sandbox Code Playgroud)
gni*_*urf 11
那是因为git处理别名的方式:
给定别名
[alias]
myalias = !string
where string是表示某些代码的任何字符串,当调用where (可能为空)参数列表时,将执行:git myalias argsargsgit
sh -c 'string "$@"' 'string' args
例如:
[alias]
banana = !echo "$1,$2,SNIP "
Run Code Online (Sandbox Code Playgroud)
并打电话
git banana one 'two two' three
Run Code Online (Sandbox Code Playgroud)
git 将执行:
sh -c 'echo "$1,$2,SNIP " "$@"' 'echo "$1,$2,SNIP "' one 'two two' three
Run Code Online (Sandbox Code Playgroud)
所以输出将是:
one,two two,SNIP one two two three
Run Code Online (Sandbox Code Playgroud)
在你的情况下,
[alias]
encrypt-for = "!g(){ echo \"once\";};$1;"
Run Code Online (Sandbox Code Playgroud)
并打电话
git encrypt-for g
Run Code Online (Sandbox Code Playgroud)
git 将执行:
sh -c 'g(){ echo "once";};$1;"$@"' 'g(){ echo "once";};$1;' g
Run Code Online (Sandbox Code Playgroud)
为清楚起见,让我以相同的形式重写:
sh -c 'g(){ echo "once";};$1;"$@"' - g
Run Code Online (Sandbox Code Playgroud)
我只是更换了'g(){ echo "once";};$1;'部分(这将是sh的$0的位置参数,这里就不再起任何作用)的伪参数-.应该很清楚它就像执行:
g(){ echo "once";};g;g
Run Code Online (Sandbox Code Playgroud)
所以你会看到:
once
once
Run Code Online (Sandbox Code Playgroud)
解决这个问题:不要使用参数!只需使用:
[alias]
encrypt-for = "!g(){ echo "once";};"
Run Code Online (Sandbox Code Playgroud)
现在,如果您确实想要使用参数,请确保根本不执行给定的尾随参数.一种可能性是添加一个尾随注释字符,如下所示:
[alias]
encrypt-for = "!g(){ echo "once";};$1 #"
Run Code Online (Sandbox Code Playgroud)
对于您的完整示例,更简洁的方法也可以将所有内容包装在函数中:
[alias]
encrypt-for = "!main() {\
case $1 in \
(github) echo github;; \
(twitter) echo twitter;; \
(facebook) echo facebook;; \
(*) echo >&2 \"error, unknown $1"\; exit 1;; \
esac \
}; main"
Run Code Online (Sandbox Code Playgroud)
希望你能理解git用别名在引擎盖下做什么!它确实附加"$@"到别名字符串并sh -c使用此字符串和给定的参数调用.