我应该在git别名脚本中使用`sh -c \“ ... \”`还是`“!f(){...;}; f”吗?

hen*_*nry 4 git bash shell git-alias

我一直在写一些带有参数的git别名,这让我非常着迷。我见过有人在运行Shell脚本

[alias]
  shAlias = !sh -c \" ... \"
Run Code Online (Sandbox Code Playgroud)

和其他与运行功能

[alias]
  fAlias = "!f() { ... ; }; f"
Run Code Online (Sandbox Code Playgroud)

似乎(一旦我掌握了Bash的速度,这还不是我的目标),我想做的任何事情都可以用这两种形式实现。

在什么情况下比其他情况更好?

除了可行性之外,还有加工差异吗?内存使用/速度/等?

tha*_*guy 6

TL; DR:使用函数方法获得最简单的命令,并在遇到任何形式的引用时切换到外部脚本。只是避免sh -c在一起。


我们可以看看git源。它以git特定方式解析引号,如果结果没有外壳元字符(包括空格),则将其作为文件执行,execlp("sh", "-c", "result \"$@\"", "result \"$@\"", args...)否则执行等效的操作。

基于此,创建别名的最佳方法肯定是创建外部脚本并使用:

[alias]
 myAlias = !/path/to/script
Run Code Online (Sandbox Code Playgroud)

它需要一个外部文件,但以其他所有方式最好:

  • 您可以使用任何所需的解释器运行。您甚至bash可以按要求运行代码,而其他形式仅允许您运行sh代码(区别就像C ++与C)。
  • 除非您愿意,否则不会启动其他外壳程序。直接gitexecve您的可执行文件。
  • 无需转义。这只是一个普通的脚本。
  • 无需任何惊喜或git知识。这只是一个脚本。

在您的建议中,亚军是:

[alias]
  fAlias = "!f() { ... ; }; f"
Run Code Online (Sandbox Code Playgroud)

这不太好,因为:

  • 不幸的是,您只能与一起运行sh,因此不能使用任何bash功能。
  • Shell总是启动的,但至少它只是一个。
  • git报价需要一些特殊的转义。
  • 您需要注意git的转义,但是通常只能在不确切知道命令执行方式的情况下进行转义,因为您只会使用函数的参数。

到目前为止,最后一个是最坏的:

[alias]
  shAlias = !sh -c \" ... \"
Run Code Online (Sandbox Code Playgroud)

这很糟糕,因为:

  • 您只能使用运行sh
  • 毫无理由,它将启动一个额外的外壳。
  • 需要git转义,又需要附加级别的sh转义。
  • 你需要知道怎样逃生代码sh,如何双重逃生与git,以及如何git追加"$@"到您的命令,如果有额外的参数,并通过附加参数$1$2

为了演示实际的区别,假设您想为此命令创建别名,以通过ssh以下方式获取远程服务器上的路径:

ssh "$1" 'echo "$PATH"'
Run Code Online (Sandbox Code Playgroud)

您可以将其原样复制粘贴到文件中,添加shebang,然后使用:

[alias]
  get-remote-path = !/path/to/my/script
Run Code Online (Sandbox Code Playgroud)

或者,您可以添加一些git转义并使用函数方法:

[alias]
  get-remote-path = "!f() { ssh \"$1\" 'echo \"$PATH\"'; }; f"
Run Code Online (Sandbox Code Playgroud)

或者,我们可以用这种sh -c方法费力地逃避并再次逃避(不,没有最后的话是行不通的):

[alias]
  get-remote-path = !sh -c 'ssh \"$1\" '\\''echo \"$PATH\"'\\' cthulhu
Run Code Online (Sandbox Code Playgroud)

显然,最好使用脚本,或者最糟糕的是使用函数方法,直到您需要可以轻松引用的更复杂的命令为止。