启动新终端时执行 zshrc 别名

zshrc alias gets executed when launching a new terminal

我正在使用 zsh 并且在我的配置中添加了另一个别名:

alias recursively_git_pull_all_repo="for dir in $(find . -name ".git"); do cd ${dir%/*}; git pull ; cd -; done"

然而,每次我打开一个新终端时,这个别名似乎都会被执行(或者至少它会大大减慢启动新终端的速度)。

如何添加这个别名而不在每次打开新终端时都启动它?

您可以将其放在函数中而不是别名中:

$ cat zshFunction

function recursively_git_pull_all_repo () {
    echo "Executing code"
    for dir in $(find . -name ".git"); do cd ${dir%/*}; git pull ; cd -; done
}

$ recursively_git_pull_all_repo
zsh: command not found: recursively_git_pull_all_repo

$ source zshFunction                                                                                                                                                      
$

$ recursively_git_pull_all_repo
Executing code
$

TL;DR (或者应该是 TL;WR - "too long, won't read"?)

alias recursively_git_pull_all_repo='for dir in **/.git(/:h); git -C $dir pull'

您至少部分正确,因为在声明别名时此命令的一部分是 运行。这有两个影响:

  1. 加载别名需要时间
  2. 别名无效

说明

您在双引号中声明了别名,这允许参数扩展。这意味着部分 $(find . -name ".git")${dir%/*} 将在声明别名时展开并替换为它们当时产生的值。

对于 $(find . -name ".git") 这意味着 . 最有可能是 $HOME 并且构造被所有 .git 目录(和其他文件-像对象)在你的主目录中。

${dir%/*} 可能会被替换为空字符串,因为 dir 很可能未设置。记住:那个时候别名本身并没有被执行,所以 dir 不会被 for 循环设置。

这意味着:

alias recursively_git_pull_all_repo="for dir in $(find . -name ".git"); do cd ${dir%/*}; git pull ; cd -; done"

将有效地保存为类似

的内容
alias recursively_git_pull_all_repo="for dir in docs/repo1/.git
docs/repo2/.git
otherdocs/repo/.git
whatever/.git; do
cd ; git pull ; cd -; done"

这将 - 幸运的是 - 由于第一个存储库之后的换行符而失败并出现 zsh: command not found: docs/repo2/.git 错误。如果没有,它会反复切换到您的主目录(cd 不带参数)并尝试执行 git pull.

解决方案

快速的解决方案是在声明别名时只使用单引号,这样命令和参数将在别名是 运行 时替换,而不是在声明时替换。

但是还有其他一些问题:

  • 如果任何目录名称包含空格,这将失败,因为 for 会将其解释为两个值
  • 如果您无法切换到找到的目录之一,git pull 将从当前目录切换到 运行。如果未在路径中的目录上设置 execute 标志,这实际上会发生。
  • 没有附加参数 find 也将列出名为 .git
  • 的非目录

相反 我建议使用 zsh 必须提供的内容:

alias recursively_git_pull_all_repo='for dir in **/.git(/:h); git -C $dir pull'
  • 您实际上不需要 find 来获取目录列表。 ** glob 将递归扩展到所有目录。因此 **/.git 将扩展到所有以 .git 作为最后一个元素的路径。
  • 您可以使用 glob 限定符来限制对满足特定条件的元素的扩展。在这种情况下 **/.git(/) 限定符 / 表示:"only directories".
  • 您还可以将历史扩展修饰符作为 glob 限定符。这是通过 : 后跟修饰符完成的 - 在本例中为 h,它删除了最后一个路径组件(如程序 dirname 或示例中的 ${dir%/*}) .
  • 您实际上不需要将目录更改为 git 存储库即可使用 git;你可以告诉 git 在哪里工作 git -C <path>
  • 因为您现在在循环中只有 运行ning 一个命令,您可以使用 for 的简短语法,意思是没有 do ...; done

有趣的事实:如果您使用 d 而不是 dir,则 for 的另一种缩写形式和选项 GLOB_STAR_SHORT 已启用(需要 zsh >= 5.2) ,您可以使用:

for d (**.git(/:h))git -C $d pull

只比您的别名长4个字符。是的,我知道完成。但是也有历史搜索。