通过脚本执行时模块未加载 (Bash)

Modules not loading when executed via a script (Bash)

我正在编写 bash 脚本来对文件执行一些命令。为此,我需要加载包含这些命令的模块。现在我可以从命令行很好地完成这些,但我想在脚本中执行检查以查看是否加载了这些模块,如果没有加载它们。这是我到目前为止所做的(我只学习了 3 天 bash,请原谅任何新手错误):

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

它进入 if 语句,意思是模块没有加载,然后说“正在加载 CDO...”,但是当我尝试使用来自这个模块的命令时,它不起作用,因为模块只是没有'好像被处决了。但是“模块已加载”执行得很好。我做错了什么?

[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

线索在全名中:“环境模块”

这些模块(不要与内核模块或任何其他模块混淆)是用于配置当前环境(用于开发环境、管理员等)的工具。

直到今天我才听说过这些。根据 these slides 他们使用包含用 Tcl 编写的声明性环境描述的模块文件。当您加载它们时,它们会转换为 shell 语法,并在当前环境中 evaled。

————————-

您的脚本无法运行的原因是 shell 脚本在新进程中执行,并且无法更改其父进程的环境 - 您从中启动它的 shell。您配置了 script 的环境(依赖于模块的命令可以在其中工作),但是当脚本退出时该环境 gone

解决方案可能是在模块文件(man modulefilehttps://linux.die.net/man/4/modulefile)中配置您的环境模块,或者“模块”文档推荐的任何内容。

或者,您可以将脚本实现为 shell 函数。 Shell 函数在当前 shell 环境中执行,因此您的模块仍将在它结束时加载。

如果你运行 type module,你可以看到module本身就是一个shell函数,这就是它能够修改当前环境的原因。

如果将以下函数附加到文件~/.bashrc并重新启动shell,您可以运行 load_modules执行它。

我认为在这种情况下不需要引用(变量等),但我还是添加了它。

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"
}

module命令,从Environment Modules软件更新当前环境会话。

正如@dan 所解释的那样,当作为 ./script.sh 执行时,您的脚本在 subshell 中 运行,在脚本执行结束时结束。因此,当 运行 以这种方式脚本更新子 shell 而不是父 shell.

的 shell 环境

如果您在当前 shell 会话中使用 source script.sh 获取脚本,您将在当前 shell 中执行 module load 命令(而不是子 shell session) 所以你将以更新的当前 shell 环境结束。