在脚本文件中执行函数:ZSH

9

我有一个 ~/scripts/git-workflow.sh 文件,其内容如下:

#!/bin/zsh

gp() {
  local cmd="git pull"
  echo "=> $cmd"
  $cmd
}

它基本上是一个更好的别名,当我使用我的别名时,它将打印出命令,以便我随着时间的推移不会忘记实际的命令。

在我的.zshrc文件中,我source ~/scripts/git-workflow.sh

在我的zsh提示符下,当我执行$ gp时,它似乎运行了该函数但失败了。

$ gp
=> git pull
gp:5: command not found: git pull

然而,如果我在命令行直接执行$ git pull,它可以正常运行。

$ git pull
Already up to date.

当我使用 bash 时,这个操作一直都很正常。但最近我改用了 zsh (感谢苹果将其设为默认值),现在执行我的脚本时出现了问题。

我需要在我的函数中添加一些特殊的格式或者在 zsh 中做出一些修改吗?


1
请参见BashFAQ#50,了解为什么即使在bash中也不应该执行此操作($cmd)。 (其中之一安全/建议的方法是@chepner建议的数组; 所以这是一个跨shell修复,而不仅仅是zsh的东西)。 - Charles Duffy
@CharlesDuffy:感谢提供链接,信息很有用!在我的情况下,我试图避免在脚本中重复命令,以便将来重构更容易。我正在修改我的脚本,改用数组方法。 - Dan L
3个回答

4

zsh 默认情况下不会对参数扩展进行单词拆分,因此在所需的命令中,gitpull 不是两个单独的单词。虽然您可以在特定的参数扩展上启用它,但更好的方法是使用数组。

gp () {
  local cmd=(git pull)
  echo "=> ${cmd[*]}"
  "${cmd[@]}"
}

4
如果您想执行存储在变量中的命令,请尝试使用(z)标志${(z)cmd}

z:使用shell解析将扩展结果拆分为单词,以查找单词,即考虑值中的任何引用。(参数扩展标志

在zsh中,默认情况下不对参数(变量)扩展执行单词拆分。

$ x="hello world 'a b c'"

# check the number of arguments with an anonymous function:
# $x is regarded as one argument as a whole
$ () { echo ${#} args; echo ${(F)@} } $x
1 args
hello world 'a b c'

${(z)x}执行“词法分割”,可以理解值中的引号:

$ () { echo ${#} args; echo ${(F)@} } ${(z)x}
3 args
hello
world
'a b c'

${=x}基于IFS执行“简单的单词拆分”;单词在空格处分隔:

$ () { echo ${#} args; echo ${(F)@} } ${=x}
5 args
hello
world
'a
b
c'

0

看起来你的命令行运行的是bash,但你正在引用的文件是zsh。这就好像在C中#include一个C++-include文件一样。这是行不通的。

在bash中,单词拆分发生在扩展$cmd之后,导致命令

git pull

在Zsh中,扩展后不会发生单词拆分。因此,该命令被理解为:
'git pull'

在你的Zsh函数中,你需要编写:
${=cmd}

这将执行git pull,但当在bash下查看时,它当然不再有效。我建议你做出决定:你想让它在bash下工作还是在Zsh下工作?

如果你同时使用两个shell - 我就是这样做的 - 为两个shell编写单独的实现,除非在bash和Zsh足够相似以至于一个实现就足够的情况下。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接