为什么在执行bash脚本时(仅在采购它时)不能加载模块?


13

我正在使用模块来控制系统上的软件包,并且已python/2.7.2作为模块安装。我有一个简单的python可执行文件python_exe.py,我将从一个简单的“ driving”脚本中调用它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

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

Answers:


13

因为该module命令是别名或shell函数(请参见module(1)中的Package Initialization ” )。当您说时,就像直接在交互式shell中键入命令一样。但是当您说时,您正在运行一个新的非交互式外壳。非交互式外壳程序通常没有设置标准别名和外壳程序功能。source runit.shmodule./runit.sh

module(1)说:“ 当将特定于Shell的初始化脚本源到Shell中时,将初始化Modules软件包和module命令。该脚本以别名或外壳函数的形式创建模块命令,……”如果需要module在脚本中运行该命令,请从脚本中找到定义该module命令的初始化source脚本。


这是使用.bashrc和.bash_profile的区别吗?其中只有一个具有初始化例程以启动模块系统以供使用。
drjrm3

我不确定您要问什么。但是:bash默认情况下会执行以下操作(这些操作可以被选项覆盖):登录外壳读取`〜/ .bash_profile`,但不是~/.bashrc,不是交互式登录外壳的交互式外壳(例如,键入bash为命令)读取~/.bashrc但不读取~/.bash_profile,并且非交互式外壳(例如,运行脚本的外壳)都不读取。…(续)
Scott

(续)…这可能是Cyrus建议的原因#!/bin/bash -i-因为该-i选项使Shell交互,因此将使其读取~/.bashrc。恕我直言,这太过分了,因为交互模式可能会带来不必要的负担(例如写入~/.bash_history)。另一方面,如果module将其定义为别名(与shell函数相对),则除非您说shopt -s expand_aliases,否则它将在非交互式shell中不起作用,因此也许Cyrus的答案是最好的。
斯科特,

4

看来,在您的系统中对shell的简单调用不会继承使用define的别名(或函数)module,因此shell无法找到它(请参见下面带有摘录的注释)。type module从提示符处尝试查看module它的当前定义。

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

关于源代码脚本和执行脚本之间的区别,您可以阅读SuperUser Sep 20092009 12月,Ubuntu 2011 2月,Unix 2011年8月,Stackoverflow 2012年12月或在许多其他地方。

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

...卸载模块文件时未设置环境变量。因此,可以加载模块文件,然后将其卸载,而无需使环境变量返回其先前状态。

因此,在脚本中执行它似乎更明智

要实现后者,我可以考虑:

  1. 要使用交互式外壳程序,忽略当前外壳程序的特定历史记录,请使用以下命令修改脚本的shebang

    #!/bin/bash -i

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

  2. 相反,如果您希望继承当前shell的特定故事,则可以尝试将其来源...但是在子shell中

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


注释
模块问答中所记

子进程(脚本)不能更改父进程环境。脚本中的模块加载只会影响脚本本身的环境。可以让脚本更改当前环境的唯一方法是提供脚本并将其读入当前进程。

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


注意模块
手册和描述页面的摘录

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

当将特定于外壳的初始化脚本源到shell中时,将初始化 Modules包和module命令。该脚本以别名或外壳函数的形式创建模块命令,并创建模块环境变量


但是他并没有试图影响父进程的环境。他只是想让他的Python可执行文件从脚本运行。此外,您的答案没有解释为什么他会收到“模块:找不到命令”错误消息。
斯科特

@斯科特谢谢。在我无意间删减了大部分答案并只张贴了一个片段之前。答案已改写。
Hastur 2015年

1
+1。  ( source runit.sh )是一个很好的答案;我没想到 并收集了很好的参考资料。
斯科特
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.