¿Por qué no puedo cargar módulos mientras ejecuto mi script bash, sino solo cuando lo obtengo?

13

Estoy usando módulos para controlar los paquetes en mi sistema y los he python/2.7.2instalado como un módulo. Tengo un ejecutable simple de Python python_exe.pyal que llamaré desde un simple script de 'conducción' runit.sh. runit.shel guión se parece a:

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

Sin embargo, cuando acabo de ejecutar ./runit.sh, me vende "módulo: comando no encontrado". Cuando source runit.sh, sin embargo, carga correctamente el módulo. ¿Por qué es esto?

drjrm3
fuente

Respuestas:

13

Debido a que el modulecomando es un alias o una función de shell (consulte " Inicialización del paquete " en el módulo (1) ). Cuando dices source runit.sh, es como escribir el modulecomando directamente en tu shell interactivo. Pero cuando dices ./runit.sh, estás ejecutando un nuevo shell no interactivo. Los shells no interactivos generalmente no tienen configurados los alias estándar y las funciones de shell.

El módulo (1) dice: “El paquete Módulos y el comando del módulo se inicializan cuando se genera un script de inicialización específico del shell en el shell. El script crea el comando del módulo , ya sea como un alias o una función de shell, ... ”. Si necesita ejecutar el modulecomando en un script, busque el script de inicialización que lo define y el modulecomando sourcedesde el script.

Scott
fuente
¿Es esta la diferencia entre usar .bashrc y .bash_profile? Solo uno de ellos tiene las rutinas de inicialización para iniciar el sistema de módulos para su uso.
drjrm3
No estoy exactamente seguro de lo que estás preguntando. Pero: bash hace lo siguiente de forma predeterminada (estas acciones pueden ser anuladas por opciones): un shell de inicio de sesión lee `~ / .bash_profile` pero no ~/.bashrc, un shell interactivo que no es un shell de inicio de sesión (por ejemplo, lo que obtienes si escribes bashcomo un comando) lee ~/.bashrcpero no ~/.bash_profile, y un shell no interactivo (por ejemplo, uno que ejecuta un script) no lee ninguno. ... (Continúa)
Scott
(Continúa) ... Esta es probablemente la razón por la cual Cyrus sugirió #!/bin/bash -i, porque la -iopción hace que el shell sea interactivo y, por lo tanto, hará que se lea ~/.bashrc. En mi humilde opinión, eso es excesivo, porque el modo interactivo puede venir con equipaje no deseado (como escribir a ~/.bash_history). Por otro lado, si modulese define como un alias (a diferencia de una función de shell), no funcionará en un shell no interactivo a menos que usted lo diga shopt -s expand_aliases, por lo que tal vez la respuesta de Cyrus sea la mejor.
Scott
4

Parece que la simple invocación del shell en su sistema no hereda el alias (o la función) con la que se define module, por lo que el shell no puede encontrarlo (vea a continuación la nota con los extractos). Pruebe type moduledesde el indicador para ver cómo modulese define actualmente.

Esencialmente con la fuente es como si escribieras cada línea del guión desde el teclado.
Tenga en cuenta que, por un lado, está heredando todo el historial específico del shell actual, pero, por el otro, el shell actual estará sujeto a todos los efectos secundarios de su script e moduleinvocación.

Sobre las diferencias entre obtener un script y ejecutarlo, puede leerlo en SuperUser Sep 2009 o Dec 2009 , Ubuntu Feb 2011 , Unix Aug 2011 , Stackoverflow Dec 2012 o en muchos otros lugares.

En este sentido, en la sección Archivos de módulo hay una advertencia :

... Las variables de entorno no se configuran al descargar un archivo de módulo. Por lo tanto, es posible cargar un archivo de módulo y luego descargarlo sin que las variables de entorno vuelvan a su estado anterior.

Por lo tanto, parece más prudente ejecutarlo en un script .

Para lograr esto último puedo pensar:

  1. Para usar un shell interactivo , descuidando el historial específico del presente shell, modificando el shebang de su script con

    #!/bin/bash -i

    Un shell interactivo lee los comandos de la entrada del usuario en un tty. Entre otras cosas, este shell lee los archivos de inicio en la activación, muestra un mensaje y permite el control del trabajo de forma predeterminada ...

  2. Si, en cambio, prefiere heredar la historia específica del presente shell, puede intentar obtenerlo ... pero en una subshell

    ( source runit.sh )
  3. Intenta encontrar el alias / función actual de modulewith y type moduleluego modifica en consecuencia tu script. Tenga en cuenta que no se puede establecer alguna variable de entorno module.
    Si lo desea, puede encontrar los scripts de inicialización en el directorio $MODULESHOME/init/<shell>.


Comentario
Como se recuerda en las preguntas y respuestas de los módulos

Un proceso secundario (script) no puede cambiar el entorno del proceso primario. La carga de un módulo en un script solo afecta el entorno del script en sí. La única forma en que puede hacer que un script cambie el entorno actual es obtener el script que lo lea en el proceso actual.

Entonces, si desea evitar modificar el entorno actual, creo que es mejor intentar cambiar el shebang (1) o buscar el script en una subshell (2). No estoy completamente seguro de la usabilidad del caso (3).


Nota
Extractos del manual y páginas de descripción de módulos

modulees una interfaz de usuario para el paquete de módulos. El modulealias o función ejecuta el modulecmdprograma y hace que el shell evalúe la salida del comando. El primer argumento para modulecmdespecifica el tipo de shell.

El paquete de módulos y el modulecomando se inicializan cuando se genera un script de inicialización específico del shell en el shell . El script crea el comando del módulo, ya sea como un alias o una función de shell, crea variables de entorno de módulos

Hastur
fuente
Pero él no está tratando de afectar el entorno del proceso principal; solo intenta que su ejecutable de Python se ejecute desde el script . Además, su respuesta no explica por qué recibe el mensaje de error "módulo: comando no encontrado".
Scott
@ Scott Gracias. Antes, sin querer, corté la mayor parte de la respuesta y publiqué solo un fragmento. Respuesta reescrita.
Hastur
1
+1.  ( source runit.sh )es una buena respuesta No lo había pensado. Y una buena colección de referencias.
Scott