zsh:在函数内执行任意别名

zsh: execute arbitrary aliases inside a function

我正在尝试编写如下函数:

function myfunc() {
  "$@"
}

实际函数还做了一些其他的事情,但关键是它环绕着任意输入命令。本质上,无论何时我们键入 myfunc <SOMETHING>,对于 <SOMETHING>.

的所有可能输入,结果应该与 <SOMETHING> 完全相同

虽然这会出现别名问题:

$ alias hello="echo hello"
$ myfunc hello
myfunc:1: command not found: hello

我尝试的另一种方法是使用 eval:

$ function myfunc2() {
  eval "$@"
}
$ $ myfunc2 hello
hello
$ myfunc2 hello '()'
(eval):1: defining function based on alias `hello'
(eval):1: parse error near `()'
$ hello '()'
hello ()

这在某些情况下有效,但在其他情况下无效。似乎 eval 最终得到了命令的不同视图,因为它已经经过了一些处理(我假设删除了单引号?)。

让我们看看这里实际发生了什么:

  • hello '()' 告诉 shell 不要解释 () (作为启动函数或其他任何东西),而是将文字字符串 () 传递给 hello.
  • myfunc2 hello '()' 告诉 shell 将字符串 hello() 传递给 myfunc2.
  • eval "$@" 告诉 shell “评估这些字符串,就好像它们是在命令行上输入的一样”。

请注意,您传递给 myfunc2 的字符串是 hello() 不带引号 。引号只是转义字符,告诉 shell 不要将 () 解释为字符串以外的任何其他内容。您还可以键入 \(\) 以将 () 作为文字字符串传递(或 \(')''('\);它们都是等价的)。这些引号 and/or 反斜杠不是字符串本身的一部分。

因此,在 shell 扩展 "$@" 之后,eval "$@" 变为 eval hello ()(没有 () 周围的引号,因为它们不是传递给 myfunc2) 的字符串,然后将其计算为好像 hello ()(同样,不带引号)已在命令行中键入。

您需要做的是重新引用 myfunc2:

的参数
% alias hello="echo hello"
% myfunc2 () {
  eval "${(q)@}"
}
% myfunc2 hello '()'
hello ()
% myfunc2 hello \(\) \(')' '('\)
hello () () ()
%