为什么我不能在执行 bash 脚本时加载模块,而只能在采购它时加载?

drj*_*rm3 13 shell bash python

我正在使用模块来控制系统上的包,并且我已python/2.7.2作为模块安装。我有一个简单的 python 可执行文件python_exe.py,我将从一个简单的“驾驶”脚本中调用它runit.shrunit.sh脚本看起来像:

#!/bin/bash
module load python/2.7.2
arg1=myarg1
arg2=15
arg3=$5
/path/to/python_exe.py -a $arg1 -b $arg2 -c $arg3
Run Code Online (Sandbox Code Playgroud)

但是,当我刚运行时./runit.sh,它向我出售“模块:未找到命令”。source runit.sh但是,当我正确加载模块时。为什么是这样?

Sco*_*ott 15

因为该module命令是别名或 shell 函数(请参阅module(1) 中的包初始化” )。当您说 时,就像将命令直接输入到交互式 shell 中一样。但是当您说 时,您正在运行一个新的非交互式外壳。非交互式 shell 通常没有设置标准别名和 shell 函数。source runit.shmodule./runit.sh

module(1)说,“当特定于 shell 的初始化脚本被导入到 shell 中时,模块包和模块命令被初始化。脚本创建模块命令,作为别名或 shell 函数,......”如果您需要module在脚本中运行命令,请从脚本中找到定义module命令的初始化脚本和source它。


Has*_*tur 5

似乎在您的系统中对 shell 的简单调用没有继承定义的别名(或函数)module,因此 shell 无法找到它(请参阅下面的注释和摘录)。尝试type module从提示中查看module它当前是如何定义的。

从本质上讲,源代码就像您从键盘编写脚本的每一行一样。
请注意,一方面您继承了当前 shell 的所有特定历史记录,但另一方面,当前 shell 将受到脚本和module调用的所有方面的影响。

关于获取脚本和执行脚本之间的差异,您可以在 SuperUser Sep 2009Dec 2009、Ubuntu Feb 2011、Unix Aug 2011、Stackoverflow Dec 2012或许多其他地方阅读。

在这方面,在Modulefiles 部分有一个警告

...卸载模块文件时未设置环境变量。因此,可以加载一个模块文件然后卸载它,而无需环境变量返回到它们之前的状态。

所以在脚本中执行它似乎更明智

为了完成后者,我可以认为:

  1. 要使用交互式 shell,忽略当前 shell 的特定历史,使用以下命令修改脚本的shebang

    #!/bin/bash -i
    
    Run Code Online (Sandbox Code Playgroud)

    交互式 shell 从 tty 上的用户输入读取命令。除其他外,这样的 shell 在激活时读取启动文件,显示提示,并默认启用作业控制......

  2. 相反,如果您更喜欢继承当前 shell 的特定故事,您可以尝试获取它......但在一个子 shell 中

    ( source runit.sh )
    
    Run Code Online (Sandbox Code Playgroud)
  3. 尝试找到modulewith的当前别名/函数,type module然后修改您的脚本。注意某些环境变量不能设置为module.
    如果需要,您可以在目录中找到初始化脚本$MODULESHOME/init/<shell>


评论
正如模块问答中所记得的那样

子进程(脚本)不能改变父进程环境。脚本中的模块加载仅影响脚本本身的环境。您可以让脚本更改当前环境的唯一方法是获取将其读入当前进程的脚本。

因此,如果您想避免修改当前环境,我认为最好尝试更改shebang (1) 或在子shell (2) 中获取脚本。我不完全确定 case(3) 的可用性。


说明
摘自模块的手册和描述页面

module是模块包的用户界面。该module别名或函数执行该modulecmd程序,并且有壳评估命令的输出。的第一个参数modulecmd指定 shell 的类型。

当特定于 shell 的初始化脚本被导入 shell 时,模块包和module命令被初始化。脚本创建模块命令,作为别名或 shell 函数,创建模块环境变量