gpt4 book ai didi

git - 为什么这个 Bash 函数在 git 别名中执行两次,为什么添加 `exit` 可以修复它?

转载 作者:太空狗 更新时间:2023-10-29 12:45:43 25 4
gpt4 key购买 nike

如果我没有显式调用 exit对于某些基于函数的 Bash 脚本,某些函数会有额外的意外执行。是什么原因造成的?在制作 git alias 时首先注意到该行为作为回答 another user's question on 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;

但是这个稍微修改过的脚本按预期执行(只运行一次函数):

#!/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;

这正是我通过 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

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

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

以下是别名/脚本的最简单版本,它给出了双重执行的不良行为:

g(){
echo "once";
};
$1;

这是执行简化别名/脚本的结果输出(执行两次的错误行为):

$ git config --global alias.encrypt-for '!g(){ echo "once";};$1;'
$ git encrypt-for g
once
once

最佳答案

这是因为 git 处理别名的方式:

给定别名

[alias]    myalias = !string

where <em>string</em> is any string that represents some code, when calling git myalias <em>args</em> where <em>args</em> is a (possibly empty) list of arguments, git will execute:

    sh -c 'string "$@"' 'string' <em>args</em>

For example:

[alias]
banana = !echo "$1,$2,SNIP "

和调用

git banana one 'two two' three

git 将执行:

sh -c 'echo "$1,$2,SNIP " "$@"' 'echo "$1,$2,SNIP "' one 'two two' three

所以输出将是:

one,two two,SNIP one two two three

在你的情况下,

[alias]
encrypt-for = "!g(){ echo \"once\";};$1;"

和调用

git encrypt-for g

git 将执行:

sh -c 'g(){ echo "once";};$1;"$@"' 'g(){ echo "once";};$1;' g

为了清楚起见,让我用等效的形式重写它:

sh -c 'g(){ echo "once";};$1;"$@"' - g

我只替换了 'g(){ echo "once";};$1;' 部分(即 sh$0 的位置参数,在这里不会发挥任何作用)通过一个伪参数 -。应该很清楚,这就像执行:

g(){ echo "once";};g;g

所以你会看到:

once
once

要解决这个问题:不要使用参数!只需使用:

[alias]
encrypt-for = "!g(){ echo "once";};"

现在,如果您真的要使用参数,请确保根本不执行给定的尾随参数。一种可能性是像这样添加尾随注释字符:

[alias]
encrypt-for = "!g(){ echo "once";};$1 #"

对于您的完整示例,更简洁的方法还可以是将所有内容包装在一个函数中:

[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"

希望您了解 git 使用别名在幕后做了什么!它实际上将 "$@" 附加到别名字符串,并使用该字符串和给定的参数调用 sh -c

关于git - 为什么这个 Bash 函数在 git 别名中执行两次,为什么添加 `exit` 可以修复它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41151579/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com