Por que não consigo carregar módulos durante a execução do meu script bash, mas apenas ao buscá-lo?

12

Estou usando módulos para controlar os pacotes no meu sistema e python/2.7.2instalei como um módulo. Eu tenho um executável python simples python_exe.pyque chamarei de um simples script 'acionador' runit.sh. runit.shscript é algo como:

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

No entanto, quando acabo de executar ./runit.sh, ele me vende "module: command not found". Quando eu source runit.sh, no entanto, ele carrega corretamente o módulo. Por que é isso?

drjrm3
fonte

Respostas:

13

Como o modulecomando é uma função de alias ou shell (consulte " Inicialização do pacote " no módulo (1) ). Quando você diz source runit.sh, é como digitar o modulecomando diretamente no seu shell interativo. Mas quando você diz ./runit.sh, está executando um novo shell não interativo. Os shells não interativos geralmente não têm os aliases padrão e as funções de shell configurados.

O módulo (1) diz: “O pacote Modules e o comando module são inicializados quando um script de inicialização específico do shell é originado no shell. O script cria o comando do módulo , como um apelido ou função de shell, ... ”Se você precisar executar o modulecomando em um script, localize o script de inicialização que define o modulecomando e sourceele a partir do script.

Scott
fonte
Essa é a diferença entre usar .bashrc e .bash_profile? Apenas um deles possui as rotinas de inicialização para iniciar o sistema do módulo para uso.
precisa saber é o seguinte
Não sei exatamente o que você está perguntando. Mas: o bash faz o seguinte por padrão (essas ações podem ser substituídas por opções): um shell de login lê `~ / .bash_profile`, mas não ~/.bashrc, um shell interativo que não é um shell de login (por exemplo, o que você obtém se digitar bashcomo um comando) lê, ~/.bashrcmas não ~/.bash_profile, e um shell não interativo (por exemplo, um executando um script) também não lê. ... (continua)
Scott
(Continua) ... É provavelmente por isso que Cyrus sugeriu #!/bin/bash -i- porque a -iopção torna o shell interativo e, portanto, fará com que ele seja lido ~/.bashrc. IMHO, isso é um exagero, porque o modo interativo pode vir com bagagem indesejada (como escrever para ~/.bash_history). Por outro lado, se modulefor definido como um alias (em oposição a uma função de shell), ele não funcionará em um shell não interativo, a menos que você diga shopt -s expand_aliases, então talvez a resposta de Cyrus seja a melhor.
Scott
4

Parece que a simples invocação do shell no seu sistema não herda o alias (ou a função) com o qual está definido module, portanto, o shell não é capaz de encontrá-lo (veja abaixo a nota com os trechos). Tente type moduleno prompt para ver como moduleele está definido atualmente.

Essencialmente com fonte é como se você escrevesse cada linha do script a partir do teclado.
Observe que, por um lado, você está herdando todo o histórico específico do shell atual, mas, por outro, o shell atual estará sujeito a todos os efeitos do seu script e moduleinvocação.

Sobre as diferenças entre a origem e a execução de um script, você pode ler no SuperUser, setembro de 2009 ou dezembro de 2009 , Ubuntu, fevereiro de 2011 , Unix, agosto de 2011 , Stackoverflow, dezembro de 2012 ou em muitos outros lugares.

A esse respeito, na seção Modulefiles , há um aviso :

... As variáveis ​​de ambiente não estão definidas ao descarregar um arquivo de módulo. Assim, é possível carregar um arquivo de módulo e, em seguida, descarregá-lo sem que as variáveis ​​de ambiente retornem ao seu estado anterior.

Portanto, parece mais sábio executá-lo em um script .

Para realizar o último, posso pensar:

  1. Para usar um shell interativo , negligenciando o histórico específico do presente shell, modificando o shebang do seu script com

    #!/bin/bash -i

    Um shell interativo lê comandos da entrada do usuário em um tty. Entre outras coisas, esse shell lê os arquivos de inicialização na ativação, exibe um prompt e ativa o controle do trabalho por padrão ...

  2. Se, em vez disso, você preferir herdar a história específica do shell atual, tente fornecê-lo ... mas em um subshell

    ( source runit.sh )
  3. Tente encontrar o alias / função atual de modulecom type modulee modifique em conseqüência o seu script. Observe que algumas variáveis ​​de ambiente não podem ser definidas para module.
    Se você quiser, pode encontrar a inicialização scripts no diretório $MODULESHOME/init/<shell>.


Comentário
Como lembrado nas perguntas e respostas dos módulos

Um processo filho (script) não pode alterar o ambiente do processo pai. Um carregamento de módulo em um script afeta apenas o ambiente para o próprio script. A única maneira de alterar um script no ambiente atual é originar o script que o lê no processo atual.

Portanto, se você quiser evitar modificar o ambiente atual, acho melhor tentar alterar o shebang (1) ou criar o script em um subshell (2). Não tenho muita certeza da usabilidade do caso (3).


Nota
Trechos das páginas de manual e descrição dos módulos

moduleé uma interface de usuário para o pacote de módulos. O modulealias ou função executa o modulecmdprograma e faz com que o shell avalie a saída do comando. O primeiro argumento para modulecmdespecificar o tipo de shell.

O pacote Modules e o modulecomando são inicializados quando um script de inicialização específico do shell é originado no shell . O script cria o comando module, como uma função de alias ou shell, cria variáveis ​​de ambiente de Módulos

Hastur
fonte
Mas ele não está tentando afetar o ambiente do processo pai; ele está apenas tentando executar seu Python executável a partir do script . Além disso, sua resposta não explica por que ele recebe a mensagem de erro "module: command not found".
Scott
@ Scott Obrigado. Antes, inadvertidamente, cortei a maior parte da resposta e postei apenas um fragmento. Resposta reescrita.
Hastur
1
+1.  ( source runit.sh )é uma boa resposta; Eu não tinha pensado nisso. E uma boa coleção de referências.
Scott Scott