bash函数中的别名作用域


9

我使用一个脚本(我没有写权限)创建一个别名来建立环境。我想创建一个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

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

Answers:


10

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

## 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

如果外壳不是交互式的,则别名不会扩展,除非使用shopt设置expand_aliases shell选项(请参阅下面的SHELL BUILTIN COMMANDS下的shopt说明)。

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

然后,执行和获取文件之间是有区别的。基本上,运行脚本会使脚本在单独的外壳中运行,而采购脚本会使脚本在当前的外壳中运行。因此,setup.sh在执行脚本时,源程序使别名可用于父外壳程序。


好吧,我正在集群上工作,并且有几个这样的“别名”脚本可用于帮助设置软件环境等。我的目标是通过获取正确的别名,然后运行(某些)别名来调用特定的环境。我宁愿在单个命令中执行此操作,而不必依次运行多个命令。
2014年

PS不幸的是,设置别名的脚本非常冗长且有点慢(因为它涉及NFS上的许多文件),因此我不希望在登录时提供所有这些信息。
追逐

@chase,但它们仅在您运行时提供setupLotsOfThings,它们仅对函数本身不可用。它们在您从中调用函数的外壳中起作用。无论如何,如果您的函数仅提供别名,为什么不只使用别名呢?例如:alias setupstuff="source aliases.sh"
terdon 2014年

是的,但是我并不担心范围本身。理想情况下,我只想将“源代码”和“运行别名”步骤合并为一个。也许可以通过3个功能来完成?函数sourceStuff(){source ...}; 函数runStuff(){someAlias; ...}; 函数setupLotsOfThings(){sourceStuff; runStuff; };
追逐

@追,是的,我想到了,但是没有用:)。您可以通过其他一些事情来扩展您的问题吗?函数只能处理这么多的复杂性,您可能不得不编写一个小的脚本。
terdon 2014年

7

实际上,您的别名在函数加载后可用!您可以在交互式外壳程序中或.bashrc执行函数后的程序中使用它们。

限制是,在读取函数定义时(而不是在评估函数时)会扩展函数定义中的别名。这是bash的局限性。所以这将工作:

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

但这不是:

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.