Zsh无法在函数内识别别名

8
这是我的.zshrc文件:
alias inst="adb install -r -d"

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

当我执行命令notify inst app.apk时,我遇到了一个错误:
notify:2: command not found: inst
  0.00s user 0.00s system 0% cpu 0.001 total

有人能够解释一下为什么这个不起作用,以及希望有办法使它起作用吗?
2个回答

5

当Shell处理命令时,除了PATH搜索等其他操作之外,它还将检查第一个令牌/参数(由空格分隔)是否属于当前环境中加载的别名。如果您要替换的别名不是第一个令牌,则不会进行替换。如果您的别名恰好不是PATH或当前目录上可执行文件的名称,则错误将向上传播到“未找到命令”。

由于您的问题涉及Z Shell,实际上zsh提供了一个较少人知道的功能,称为全局别名。如果使用-g标志声明了别名,zsh将对任何标记进行适当的替换,而不仅仅是第一个标记,无论顺序如何。

alias -g inst="adb install -r -d"应该可以达到效果。

请注意,出于可移植性考虑,这是一个zsh专有的功能,并确保您编写的任何脚本都具有一个shebang行,调用zsh shell:#!/usr/bin/env zsh

我还建议不要在重要的或生产脚本中使用zsh全局别名。对于个人使用,这是完全可以的。


非常感谢。不确定你是如何找到它的,但这真是神奇。真的帮了我很多! - Rewanth Tammana

1

不要在脚本中使用别名

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

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

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

几乎总是,我们希望别名执行的任何操作都可以通过函数更有效地完成。

一个巧妙的解决方案

如果这只是为了自己编写快速脚本,并且使用了您在.zshrc中的别名,则仍有一种方法可行。

alias foo='echo hello'

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

bar foo # => hello

别名替换

来自别名手册页

每个简单命令的第一个单词(如果未加引号)将被检查以查看是否有别名。如果有,则该单词将被替换为别名的文本。别名名称和替换文本可以包含任何有效的 shell 输入,包括 shell 元字符,但别名名称不能包含“=”。
替换文本的第一个单词会被测试以查看是否有别名,但与正在展开的别名相同的单词不会被再次展开。这意味着可以将 ls 别名设置为“ls -F”,而 Bash 不会尝试递归展开替换文本。
除非使用 shopt 设置 expand_aliases shell 选项,否则在 shell 非交互时不会展开别名。
关于别名的定义和使用的规则有些令人困惑。Bash 在执行该行上的任何命令之前始终读取至少一行完整的输入。别名在读取命令时展开,而不是在执行命令时展开。因此,在与另一个命令位于同一行的别名定义将在读取下一行输入之前不会生效。该行别名定义后面的命令不受新别名的影响。当执行函数时,此行为也是一个问题。由于函数定义本身是一个复合命令,因此在读取函数定义时展开别名,而不是在执行函数时展开别名。因此,在函数中定义的别名在执行该函数之后才可用。为了安全起见,始终将别名定义放在单独的一行上,并且不要在复合命令中使用别名。

1
这个问题是关于zsh而不是bash的。由于zsh是bash的功能超集,您在回答中引用bash文档时会错过一些东西。 - JoshuaRLi
这对我来说看起来仍然非常准确。你在我的引用中发现了一些不适用于zsh的内容吗?尽管如此,我刚刚看到了你的解决方案,并且喜欢它的全局别名想法,它确实利用了zsh是超集的事实!但是为了回答OP,仍然使用普通别名,我仍然认为我的答案是准确的。 - Ulysse BN

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