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

Should I use `sh -c \"...\"` or `"!f() {... ; }; f" in git alias scripts?

我一直在尝试编写带有参数的 git 别名。我见过一些人 运行 shell 脚本

[alias]
  shAlias = !sh -c \" ... \"

和其他运行函数与

[alias]
  fAlias = "!f() { ... ; }; f"

似乎(一旦我加快了 Bash 的速度——这不是我现在的状态)我想做的任何事情都可以用任何一种形式完成。

在什么情况下一种优于另一种?

除了可行性之外,是否存在处理差异?内存使用/速度/等?

如果适用,请优先使用该函数,因为它直接由 shell 执行别名的任何对象执行。使用 sh -c '...' 会导致 另一个 进程启动。

TL;DR:对最简单的命令使用函数方法,一旦遇到任何类型的引用问题,就切换到外部脚本。一起避免 sh -c


我们可以have a look at the git source。它以 git 特定方式解析引号,如果结果没有 shell 元字符(包括 space)则作为文件执行,否则执行 execlp("sh", "-c", "result \"$@\"", "result \"$@\"", args...) 的等价物。

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

[alias]
 myAlias = !/path/to/script

它需要一个外部文件,但在所有其他方面它更好:

  • 您 运行 与您想要的任何口译员。你甚至可以 运行 bash 代码,因为你问,而其他形式只允许你 运行 sh 代码(区别就像 C++ 与 C)。
  • 除非您愿意,否则不会启动其他 shell。 gitexecve 直接执行您的可执行文件。
  • 不需要转义。这只是一个普通的脚本。
  • 没有惊喜,也不需要 git 知识。这只是一个脚本。

根据您的建议,运行最后一项是:

[alias]
  fAlias = "!f() { ... ; }; f"

这没那么棒,因为:

  • 很遗憾,您只能 运行 使用 sh,因此不能使用任何 bash 功能。
  • 一个shell总是启动,但至少它只是一个。
  • 引号需要一些 git 特定的转义。
  • 您需要注意 git 的转义,但通常无需确切知道它是如何执行命令的,因为您将只使用函数的参数。

最后一个是迄今为止最差的:

[alias]
  shAlias = !sh -c \" ... \"

这很糟糕,因为:

  • 您只能 运行 与 sh
  • 它会无缘无故地开始额外的 shell。
  • 您需要 git 转义和额外的 sh 转义级别。
  • 您需要知道如何转义 sh 的代码,如何使用 git 对其进行双重转义,以及 git 如何将 "$@" 附加到您的命令如果有附加参数,则将附加参数作为 </code>、<code> 传递。

为了演示实际差异,假设您想为此命令创建别名以通过 ssh:

获取远程服务器上的路径
ssh "" 'echo "$PATH"'

您可以将其逐字复制粘贴到文件中,添加一个 shebang,然后使用:

[alias]
  get-remote-path = !/path/to/my/script

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

[alias]
  get-remote-path = "!f() { ssh \"\" 'echo \"$PATH\"'; }; f"

或者我们可以用sh -c的方法费力地逃避再逃避(不行,没有硬道理不行):

[alias]
  get-remote-path = !sh -c 'ssh \"\" '\''echo \"$PATH\"'\' cthulhu

显然,最好使用脚本,或者在最坏的情况下使用函数方法,直到您需要可以轻松引用的更复杂的命令。