Почему я не могу загрузить модули при выполнении моего bash-скрипта, а только при его получении?

13

Я использую модули для управления пакетами в моей системе, и я python/2.7.2установил их как модуль. У меня есть простой исполняемый файл Python, python_exe.pyкоторый я собираюсь вызывать из простого сценария «вождения» runit.sh. runit.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, однако, он правильно загружает модуль. Почему это?

drjrm3
источник

Ответы:

13

Поскольку moduleкоманда является псевдонимом или функцией оболочки (см. « Инициализация пакета » в модуле (1) ). Когда вы говорите source runit.sh, это похоже на ввод moduleкоманды непосредственно в интерактивную оболочку. Но когда вы говорите ./runit.sh, вы запускаете новую неинтерактивную оболочку. Неинтерактивные оболочки обычно не имеют стандартных псевдонимов и настроенных функций оболочки.

Модуль (1) говорит: «Пакет Modules и команда модуля инициализируются, когда в оболочку создается специфический для оболочки скрипт инициализации. Сценарий создает команду модуля в виде псевдонима или функции оболочки… ». Если вам нужно выполнить moduleкоманду в сценарии, найдите сценарий инициализации, который определяет moduleкоманду и sourceее из сценария.

Скотт
источник
В этом ли разница между использованием .bashrc и .bash_profile? Только у одного из них есть процедуры инициализации для запуска системы модулей для использования.
drjrm3
Я не совсем уверен, что вы спрашиваете. Но: bash по умолчанию выполняет следующие действия (эти действия могут быть переопределены параметрами): оболочка входа в систему читает `~ / .bash_profile`, но не ~/.bashrcинтерактивную оболочку, которая не является оболочкой входа в систему (например, то, что вы получаете, если вводить bashкак команда) читает, ~/.bashrcно не читает ~/.bash_profile, а неинтерактивная оболочка (например, запускающая скрипт) не читает ни того, ни другого. … (Продолжение)
Скотт
(Продолжение)… Вероятно, поэтому Cyrus и предложил, #!/bin/bash -iпотому что эта -iопция делает оболочку интерактивной и, следовательно, заставляет ее читать ~/.bashrc. ИМХО, это излишне, потому что интерактивный режим может прийти с нежелательным багажом (например, письмо ~/.bash_history). С другой стороны, если moduleон определен как псевдоним (в отличие от функции оболочки), он не будет работать в неинтерактивной оболочке, если вы не скажете shopt -s expand_aliases, поэтому, возможно, ответ Сайруса будет лучшим.
Скотт
4

Кажется, что простой вызов оболочки в вашей системе не наследует псевдоним (или функцию), с которой он определен module, поэтому оболочка не может его найти (см. Примечание с выдержками). Попробуйте type moduleиз подсказки посмотреть, как moduleоно определяется в данный момент.

По сути с исходным кодом это все равно, что написать каждую строку сценария с клавиатуры.
Обратите внимание, что с одной стороны вы наследуете всю конкретную историю текущей оболочки, но, с другой стороны, текущая оболочка будет подвергаться воздействию всех сторон вашего сценария и moduleвызова.

О различиях между созданием сценария и его выполнением вы можете прочитать в SuperUser Sep 2009 или Dec 2009 , Ubuntu Feb 2011 , Unix Aug 2011 , Stackoverflow Dec 2012 или во многих других местах.

В связи с этим в Modulefiles разделе есть предупреждение :

... Переменные окружения сбрасываются при выгрузке файла модуля. Таким образом, можно загрузить файл модуля, а затем выгрузить его, не возвращая переменным среды их прежнее состояние.

Так что кажется более разумным выполнить его в сценарии .

Для достижения последнего я могу думать:

  1. Чтобы использовать интерактивную оболочку , пренебрегая конкретной историей существующей оболочки, измените шебанг вашего скрипта с помощью

    #!/bin/bash -i

    Интерактивная оболочка читает команды из пользовательского ввода на tty. Среди прочего, такая оболочка читает файлы запуска при активации, отображает приглашение и по умолчанию включает управление заданиями ...

  2. Если вместо этого вы предпочитаете унаследовать конкретную историю существующей оболочки, вы можете попытаться получить ее из источника ... но в подоболочке

    ( source runit.sh )
  3. Попробуйте найти текущий псевдоним / функцию moduleс type moduleпоследующим изменением вашего скрипта. Обратите внимание, что некоторые переменные окружения не могут быть установлены для module.
    Если вы хотите, вы можете найти сценарии инициализации в каталоге $MODULESHOME/init/<shell>.


Комментарий
Как вспомнили в Q & A модулей

Дочерний процесс (скрипт) не может изменить среду родительского процесса. Загрузка модуля в сценарии влияет только на среду самого сценария. Единственный способ изменить сценарий в текущей среде - это создать сценарий, который считывает его в текущий процесс.

Поэтому, если вы хотите избежать изменения текущей среды, я думаю, что лучше попытаться изменить shebang (1) или создать скрипт в подоболочке (2). Я не совсем уверен в юзабилити кейса (3).


Примечание
Выдержки из страниц руководства и описания модулей

moduleпользовательский интерфейс к пакету модулей moduleПсевдоним или функция выполняет modulecmdпрограмму и имеет оболочку оценить вывод команды. Первый аргумент modulecmdуказывает тип оболочки.

Пакет Modules и moduleкоманда инициализируются, когда в оболочку поступает специфический для оболочки скрипт инициализации . Сценарий создает команду модуля в виде псевдонима или функции оболочки, создает переменные среды Modules

Hastur
источник
Но он не пытается влиять на среду родительского процесса; он только пытается заставить свой исполняемый файл Python запускаться из скрипта . Кроме того, ваш ответ не объясняет, почему он получает сообщение об ошибке «module: command not found».
Скотт
@ Скотт Спасибо. Прежде чем я по неосторожности вырезал большую часть ответа и выложил только фрагмент. Ответ переписан.
Hastur
1
+1.  ( source runit.sh )хороший ответ; Я не думал об этом. И хорошая коллекция ссылок.
Скотт