linuxbashenvironment-modules

Modules not loading when executed via a script (Bash)


I'm writing a bash script to perform some commands on files. In order to do that, I need to load the modules which contain these commands. Now I can do these from the command line just fine, but I wanted to implement a check in a script to see if those modules are loaded, and if they are not, to load them. Here is what I have done so far (I am just 3 days into learning bash, so excuse any newbie errors):

#A list with all the necessary modules
declare -a modules=("CDO/1.9.7-gompi-2019a" "ncview/2.1.7-gompi-2019a")

echo "Running script"
echo ""

#Check if modules are loaded. If not, load them
for mod in "${modules[@]}"
do
    module is-loaded $mod

    if [ $? = 1 ]
    then
        echo "Loading ${mod}"
        module load $mod
    else
        echo "${mod} is already loaded"
    fi
done

echo ""
echo "Finished running script"

It enters the if statement, meaning the module is not loaded, and then says "Loading CDO...", but when I try to use commands from this module, it does not work because the module just doesn't seem to be executed. But the "module is-loaded" executes just fine. What am I doing wrong?

[diyon@login2 scripts]$ ./script.sh
Running script

Loading CDO/1.9.7-gompi-2019a
Loading ncview/2.1.7-gompi-2019a

Finished running script
[diyon@login2 scripts]$ cdo
-bash: cdo: command not found

Solution

  • The clue is in the full name: “Environment Modules”

    These modules (not to be confused with kernel modules or any other modules), are a tool used to configure the current environment (for development environments, administrators etc.).

    I had not heard of these until today. According to these slides they use module files containing a declarative environment description written in Tcl. When you load them, they are converted to shell syntax, and evaled in the current environment.

    ———————-

    The reason your script did not work is that a shell script executes in a new process, and can not change the environment of its parent process - the shell you launched it from. You configured the environment of the script (where the module dependant commands would have worked), but that environment is gone when the script exits.

    The solution is probably to configure your environment modules in a module file (man modulefile or https://linux.die.net/man/4/modulefile), or whatever is recommended by the “Modules” documentation.

    Or, you can implement your script as a shell function. Shell functions execute in the current shell environment, so your modules will still be loaded at the end of it.

    If you run type module, you can see that module itself is a shell function, which is why it’s able to modify the current environment.

    If you append the following function to the file ~/.bashrc and restart the shell, you can run load_modules to execute it.

    I think quoting (variables etc) is unnecessary in this situation, but I added it anyway.

    load_modules ()
    {
        # A list with all the necessary modules
        local -a modules=('CDO/1.9.7-gompi-2019a'
                          'ncview/2.1.7-gompi-2019a')
        local mod
    
        echo "Running function"
        echo
    
        # Check if modules are loaded. If not, load them
        for mod in "${modules[@]}"
        do
            if module is-loaded "$mod"
            then
                echo "$mod is already loaded"
            else
                echo "Loading $mod…"
                module load "$mod"
            fi
        done
    
        echo
        echo "Finished running the function"
    }