Alias scoping in bash functions

bash

I use a script (which I do not have write access to) that creates a bunch of aliases to set up an environment. I would like to create a bash function to setup my environment, but it seems that the aliases do not survive to the function body.

Here's a minimal example:

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

.

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

.

Now, if I simply source aliases.sh interactively, things work as expected:

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

However, if I instead call the function defined in my .bashrc, it doesn't recognize the alias after sourcing its definition:

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

What is going on here? Is there something I am missing about the scope of the alias command when used in a function?

Edit: I'll add some details beyond the minimal example to shine some light on what I'm trying to accomplish.

For my work I develop and run a lot of software on a cluster and/or grid. I have several projects that require completely different environments, such as different gcc versions, specific software releases, config and data PATHs, and various environment variables. Administrators provide the scripts to set up various things, usually by defining shell functions or aliases, which invoke other functions or aliases or run various scripts. To me, it's a black box.

I'd like to setup my own various environments with a single command. Currently, I do something like:

[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

These commands generally have to be run in order. My idea basically was to just copy the above lines into a function block, but as original example shows, that simply doesn't work. Alternative workarounds are more than welcome!

Best Answer

An alternative solution is to paste those commands into a text file instead of a function block. Something like:

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

Save that as setup1.sh wherever you like. The trick is to then source this file, not execute it:

$ source setup1.sh

That will run the aliases that are in the script and also make them available to your current shell.

You can further simplify the process by adding this to your .bashrc:

alias setupLotsOfThings="source setup1.sh"

Now you can simply run setupLotsOfThings and get the behavior you wanted from the function.


Explanation

There are two issues here. First, aliases are not available to the function they are declared in but only once that function has exited and second that aliases are not available within scripts. Both are explained in the same section of man bash:

Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see the description of shopt under SHELL BUILTIN COMMANDS below).

The rules concerning the definition and use of aliases are somewhat confusing. Bash always reads at least one complete line of input before executing any of the commands on that line. Aliases are expanded when a command is read, not when it is executed. Therefore, an alias definition appearing on the same line as another command does not take effect until the next line of input is read. The commands following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are executed. Aliases are expanded when a function definition is read, not when the function is executed, because a function definition is itself a compound command. As a consequence, aliases defined in a function are not
available until after that function is executed.
To be safe, always put alias definitions on a separate line, and do not use alias in com‐ pound commands.

Then, there is the difference between executing and sourcing a file. Basically, running a script makes it run in a separate shell while sourcing it makes it run in the current shell. So, sourcing setup.sh makes the aliases available to the parent shell while executing it as a script would not.

Related Question