Чому я не можу завантажувати модулі під час виконання мого скрипта bash, але лише під час його пошуку?


13

Я використовую модулі для управління пакетами в своїй системі, і я python/2.7.2встановив її як модуль. У мене є простий виконуваний пітон, на 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, однак, він правильно завантажує модуль. Чому це?

Відповіді:


13

Оскільки moduleкоманда - це псевдонім або оболонка (див. " Ініціалізація пакета " в модулі (1) ). Коли ви говорите source runit.sh, це як введення moduleкоманди безпосередньо у вашу інтерактивну оболонку. Але коли ти кажеш ./runit.sh, ти працюєш з новою неінтерактивною оболонкою. Неінтерактивні оболонки зазвичай не мають стандартних псевдонімів та функцій оболонки.

Модуль (1) говорить: "Пакет Модулі та команда модуля ініціалізуються, коли специфічний для оболонки сценарій ініціалізації розміщений у оболонці. Сценарій створює команду модуля , або як псевдонім, або функцію оболонки ... ”Якщо вам потрібно виконати moduleкоманду в сценарії, знайдіть скрипт ініціалізації, який визначає moduleкоманду та sourceїї з сценарію.


Чи різниця між використанням .bashrc та .bash_profile? Лише одна з них має процедури ініціалізації для запуску модульної системи для використання.
drjrm3

Я не зовсім впевнений, про що ви питаєте. Але: bash виконує наступні за замовчуванням (ці дії можуть бути замінені за параметрами): оболонка входу читає `~ / .bash_profile`, але ні ~/.bashrc, інтерактивна оболонка, яка не є оболонкою для входу (наприклад, що ви отримуєте, якщо вводити bashяк команда) читає, ~/.bashrcале ні ~/.bash_profile, і неінтерактивна оболонка (наприклад, одна, яка виконує сценарій) не читає жодного. … (Продовжив)
Скотт

(Продовжував) ... Це, мабуть, саме тому Сайрус запропонував #!/bin/bash -i- оскільки -iопція робить оболонку інтерактивною, а тому змусить її прочитати ~/.bashrc. IMHO, це надмірно, тому що в інтерактивному режимі може йти небажаний багаж (як, наприклад, написання ~/.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визначення типу оболонки.

Пакет Модулі та moduleкоманда ініціалізуються, коли специфічний для оболонки сценарій ініціалізації розміщений у оболонці . Сценарій створює команду модуля або як псевдонім або оболонку, створює змінні середовища Модулі


Але він не намагається впливати на середовище батьківського процесу; він лише намагається отримати його виконуваний Python для запуску зі сценарію . Крім того, ваша відповідь не пояснює, чому він отримує повідомлення про помилку «модуль: команда не знайдено».
Скотт

@Scott Дякую Перш ніж я ненароком вирізав більшу частину відповіді і розмістив лише фрагмент. Відповідь переписана.
Hastur

1
+1.  ( source runit.sh )- хороша відповідь; Я не думав про це. І хороша колекція довідок.
Скотт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.