Bash 函数中的别名作用域

Bash 函数中的别名作用域

我使用一个脚本(我没有写入权限)创建了一堆别名来设置环境。我想创建一个 bash 函数来设置我的环境,但似乎别名没有保留到函数主体中。

这是一个简单的例子:

# aliases.sh
alias fooAlias='echo "this will never work!"'  

# .bashrc
function setupLotsOfThings() {
    source aliases.sh
    fooAlias
}

现在,如果我仅以aliases.sh交互方式进行获取,事情就会按预期进行:

[mycomputer]~/ $ source aliases.sh
[mycomputer]~/ $ fooAlias
this will never work!

但是,如果我调用 .bashrc 中定义的函数,则在获取其定义后它无法识别别名:

[mycomputer]~/ $ setupLotsOfThings
-bash: fooAlias: command not found

alias这是怎么回事?在函数中使用命令时,我是否遗漏了命令的范围?

编辑:我将在最小示例之外添加一些细节,以阐明我想要完成的任务。

我的工作是在集群和/或网格上开发和运行大量软件。我有几个项目需要完全不同的环境,例如不同的 gcc 版本、特定的软件版本、配置和数据 PATH 以及各种环境变量。管理员提供脚本来设置各种内容,通常是通过定义 shell 函数或别名来调用其他函数或别名或运行各种脚本。对我来说,这是一个黑匣子。

我想用一个命令设置我自己的各种环境。目前,我这样做:

[mycomputer]~/ $ source /some/environment/setup/script.sh
[mycomputer]~/ $ aliasToSetupSomeSoftwareVersion    #this was defined in the above
[mycomputer]~/ $ anotherAliasForOtherSoftware
[mycomputer]~/ $ source /maybe/theres/another/script.sh
[mycomputer]~/ $ runSomeOtherSetup      # this was defined in the new script

这些命令通常必须按顺序运行。我的想法基本上是将上面的行复制到一个功能块中,但正如原始示例所示,这根本行不通。非常欢迎其他解决方法!

答案1

另一种解决方案是将这些命令粘贴到文本文件中,而不是功能块中。例如:

## This is needed to make the sourced aliases available
## within the script.
shopt -s expand_aliases

source /some/environment/setup/script.sh
aliasToSetupSomeSoftwareVersion
anotherAliasForOtherSoftware
source /maybe/theres/another/script.sh
runSomeOtherSetup

将其保存为setup1.sh你喜欢的任何位置。诀窍是来源此文件,不要执行它:

$ source setup1.sh

这将运行脚本中的别名并使其可供当前 shell 使用。

您可以通过将其添加到以下内容来进一步简化流程.bashrc

alias setupLotsOfThings="source setup1.sh"

现在您可以简单地运行setupLotsOfThings并从函数中获取您想要的行为。


解释

这里有两个问题。首先,别名不可用于声明它们的函数,但只有在该函数退出后才可用;其次,别名在脚本中不可用。两者在同一个部分中进行了解释man bash

当 shell 不是交互式的时,别名不会展开,除非使用 shopt 设置 expand_aliases shell 选项(参见下面 Shell 内建命令 下对 shopt 的描述)。

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

然后,执行文件和获取文件源之间存在差异。基本上,运行脚本会使它在单独的 shell 中运行,而获取文件源会使它在当前 shell 中运行。因此,获取文件源setup.sh会使别名可供父 shell 使用,而执行脚本则不会。

答案2

实际上,您的别名在函数加载后即可使用!您可以在交互式 shell 中使用它们,也可以在.bashrc执行函数后使用它们。

限制是,函数定义中的别名在读取函数定义时展开,而不是在评估函数时展开。这是 bash 的限制。因此这将有效:

function setupLotsOfThings() {
    source aliases.sh
}
setupLotsOfThings
fooAlias

但不是这个:

function setupLotsOfThings() {
    source aliases.sh
}
function useTheAliases() {
    fooAlias
}
setupLotsOfThings
useTheAliases

如果您需要可在函数内部使用且可在解析函数后定义的别名,请将其改为函数。请记住,您可以使用command内置命令从同名函数调用外部命令。

相关内容