Zsh 无法识别函数内的别名

Cal*_*res 8 zsh zshrc

这是我的.zshrc

alias inst="adb install -r -d"

notify() {
  start=$(date +%s)
  "$@"
  notify-send "\"$(echo $@)\" took $(($(date +%s) - start)) seconds to finish"
}
Run Code Online (Sandbox Code Playgroud)

当我运行命令时notify inst app.apk,出现错误:

notify:2: command not found: inst
  0.00s user 0.00s system 0% cpu 0.001 total
Run Code Online (Sandbox Code Playgroud)

谁能解释一下为什么这行不通,并希望有一种方法让它发挥作用?

Jos*_*RLi 5

当 shell 处理命令(例如PATH搜索)时,它会检查第一个标记/参数(空格分隔)是否属于当前环境中加载的别名。如果您尝试替换的别名不是第一个标记,则替换不会发生。如果您的别名碰巧不是PATH当前目录中可执行文件的名称,则错误将传播回command not found.

由于您的问题是关于 Z Shell 的,zsh因此实际上提供了一个鲜为人知的功能,称为全局别名。如果使用该标志声明别名-gzsh则不仅会对第一个标记进行适当的替换,而且还会对任何标记进行适当的替换,无论顺序如何。

alias -g inst="adb install -r -d"应该可以解决问题。

请记住,这是zsh出于可移植性原因的唯一功能,并确保您编写的任何脚本都有调用 shell 的 shebang 行zsh#!/usr/bin/env zsh

我还建议不要zsh在重要或生产脚本中使用全局别名。对于个人使用来说,完全没问题。


Uly*_* BN 1

不要在脚本中使用别名

首先,根据高级 bash 脚本编写指南

在脚本中,别名的用处非常有限。

因此,您可以考虑不使用别名,而是使用函数(仍然来自同一页面,下 2 段):

几乎总是,无论我们希望别名做什么,都可以通过函数更有效地完成。

一个黑客解决方案

如果这是为了使用您的 中的别名为您自己编写一个快速脚本.zshrc,那么仍然有出路。

alias foo='echo hello'

bar() {
    `alias "$@" | cut -d\' -f2`
}

bar foo # => hello
Run Code Online (Sandbox Code Playgroud)

别名替换

来自别名手册页

每个简单命令的第一个单词(如果未加引号)将被检查以查看它是否有别名。如果是这样,该单词将被别名的文本替换。别名和替换文本可以包含任何有效的 shell 输入,包括 shell 元字符,但别名不能包含“=”。

替换文本的第一个单词会进行别名测试,但与正在扩展的别名相同的单词不会再次扩展。这意味着可以将 ls 别名为“ls -F”,并且 Bash 不会尝试递归地扩展替换文本。

当 shell 不具有交互性时,别名不会展开,除非使用 shopt 设置 Expand_aliases shell 选项。

有关别名的定义和使用的规则有些令人困惑。在执行该行上的任何命令之前,Bash 总是至少读取一整行输入。别名在读取命令时展开,而不是在执行命令时展开。因此,与另一个命令出现在同一行的别名定义在读取下一行输入之前不会生效。该行上别名定义后面的命令不受新别名的影响。执行函数时,此行为也是一个问题。别名在读取函数定义时展开,而不是在执行函数时展开,因为函数定义本身就是复合命令。因此,函数中定义的别名只有在执行该函数之后才可用。为了安全起见,请始终将别名定义放在单独的行上,并且不要在复合命令中使用别名。