Dlaczego nie mogę załadować modułów podczas wykonywania skryptu bash, ale tylko podczas jego pobierania?

13

Używam modułów do kontrolowania pakietów w moim systemie i python/2.7.2zainstalowałem jako moduł. Mam prosty plik wykonywalny Pythona, python_exe.pyktóry zamierzam wywołać z prostego skryptu „sterującego” runit.sh. runit.shskrypt wygląda mniej więcej tak:

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

Jakkolwiek, kiedy właśnie uruchamiam ./runit.sh, sprzedaje mi „moduł: nie znaleziono polecenia”. Kiedy source runit.shjednak poprawnie ładuje moduł. Dlaczego to?

drjrm3
źródło

Odpowiedzi:

13

Ponieważ modulepolecenie jest aliasem lub funkcją powłoki (patrz „ Inicjalizacja pakietu ” w module (1) ). Kiedy mówisz source runit.sh, to tak, jakbyś wpisał modulepolecenie bezpośrednio w interaktywnej powłoce. Ale kiedy mówisz ./runit.sh, uruchamiasz nową, nieinteraktywną powłokę. Nieinteraktywne powłoki zasadniczo nie mają skonfigurowanych standardowych aliasów i funkcji powłoki.

moduł (1) mówi: „Pakiet Modules i polecenie modułu są inicjowane, gdy skrypt powłoki inicjuje specyficzny dla powłoki. Skrypt tworzy komendę modułową jako alias lub funkcję powłoki… ”Jeśli chcesz uruchomić modulekomendę w skrypcie, znajdź skrypt inicjujący, który definiuje modulekomendę i sourceskrypt ze skryptu.

Scott
źródło
Czy to jest różnica między używaniem .bashrc i .bash_profile? Tylko jedna z nich ma procedury inicjalizacji w celu uruchomienia systemu modułów do użycia.
drjrm3
Nie jestem do końca pewien, o co pytasz. Ale: bash domyślnie wykonuje następujące czynności (te akcje można zastąpić opcjami): powłoka logowania odczytuje `~ / .bash_profile`, ale nie ~/.bashrcinteraktywna powłoka, która nie jest powłoką logowania (np. Co otrzymujesz, jeśli wpiszesz bashjako polecenie) czyta, ~/.bashrcale nie czyta ~/.bash_profile, a nieinteraktywna powłoka (np. uruchamiająca skrypt) nie czyta żadnej. … (Ciąg dalszy)
Scott,
(Ciąg dalszy)… Prawdopodobnie dlatego Cyrus zasugerował #!/bin/bash -i- ponieważ ta -iopcja powoduje, że powłoka jest interaktywna i dlatego powoduje jej odczyt ~/.bashrc. IMHO, to przesada, ponieważ tryb interaktywny może pochodzić z niechcianego bagażu (jak pisanie na ~/.bash_history). Z drugiej strony, jeśli modulejest zdefiniowany jako alias (w przeciwieństwie do funkcji powłoki), nie będzie działał w powłoce nieinteraktywnej, chyba że powiesz shopt -s expand_aliases, więc może odpowiedź Cyrusa jest najlepsza.
Scott,
4

Wygląda na to, że proste wywołanie powłoki w twoim systemie nie dziedziczy zdefiniowanego aliasu (lub funkcji) module, więc powłoka nie jest w stanie jej znaleźć (patrz poniżej uwaga z fragmentami). Spróbuj type modulez wiersza polecenia, aby zobaczyć, jak moduleto jest obecnie zdefiniowane.

Zasadniczo ze źródłem jest tak, jakbyś pisał każdą linię skryptu z klawiatury.
Zauważ, że z jednej strony dziedziczysz całą konkretną historię bieżącej powłoki, ale z drugiej strony bieżąca powłoka będzie podlegać wszystkim efektom skryptu i modulewywołaniu.

O różnicach między źródłem skryptu a jego uruchomieniem można przeczytać w SuperUser wrzesień 2009 lub grudzień 2009 , Ubuntu luty 2011 , Unix sierpień 2011 , Stackoverflow grudzień 2012 lub w wielu innych miejscach.

W związku z tym w sekcji Moduły plików znajduje się ostrzeżenie :

... Zmienne środowiskowe są rozbrojone podczas rozładowywania pliku modułu. Dlatego możliwe jest załadowanie pliku modułu, a następnie zwolnienie go bez powrotu zmiennych środowiskowych do poprzedniego stanu.

Bardziej rozsądne wydaje się wykonanie go w skrypcie .

Aby osiągnąć to drugie, mogę pomyśleć:

  1. Aby użyć interaktywnej powłoki , zaniedbując konkretną historię obecnej powłoki, modyfikując shebang skryptu za pomocą

    #!/bin/bash -i

    Interaktywna powłoka czyta polecenia z danych wprowadzanych przez użytkownika na terminalu tty. Między innymi taka powłoka czyta pliki startowe podczas aktywacji, wyświetla monit i domyślnie włącza kontrolę zadań ...

  2. Jeśli zamiast tego wolisz odziedziczyć konkretną historię obecnej powłoki, możesz spróbować ją zdobyć ... ale w podpowłoce

    ( source runit.sh )
  3. Spróbuj znaleźć bieżący alias / funkcję, modulea type modulenastępnie zmodyfikuj w konsekwencji swój skrypt. Uwaga: nie można ustawić niektórych zmiennych środowiskowych module.
    Jeśli chcesz, możesz znaleźć skrypty inicjujące w katalogu $MODULESHOME/init/<shell>.


Komentarz
Jak zapamiętano w pytaniach i odpowiedziach dotyczących modułów

Proces potomny (skrypt) nie może zmienić środowiska procesu macierzystego. Ładowanie modułu w skrypcie wpływa tylko na środowisko dla samego skryptu. Jedynym sposobem na zmianę skryptu w bieżącym środowisku jest źródło skryptu, który wczytuje go do bieżącego procesu.

Więc jeśli chcesz uniknąć modyfikacji obecnego środowiska, myślę, że lepiej jest spróbować zmienić shebang (1) lub źródło skryptu w podpowłoce (2). Nie jestem całkowicie pewien użyteczności skrzynki (3).


Uwaga
Fragmenty stron podręcznika i opisów modułów

moduleto interfejs użytkownika do pakietu modułów. moduleAlias lub funkcję realizuje modulecmdprogram i ma powłokę ocenić wyjścia polecenia. Pierwszy argument modulecmdokreślający typ powłoki.

Pakiet Modules i modulekomenda są inicjowane, gdy skrypt inicjujący specyficzny dla powłoki jest pobierany do powłoki . Skrypt tworzy polecenie modułu, jako funkcję aliasu lub powłoki, tworzy zmienne środowiskowe Modules

Hastur
źródło
Ale nie próbuje wpływać na środowisko procesu macierzystego; stara się tylko, aby jego plik wykonywalny w Pythonie działał ze skryptu . Poza tym twoja odpowiedź nie wyjaśnia, dlaczego pojawia się komunikat o błędzie „moduł: nie znaleziono polecenia”.
Scott,
@Scott Thanks. Zanim przypadkowo wyciąłem większą część odpowiedzi i zamieściłem tylko fragment. Odpowiedź przepisana.
Hastur
1
+1.  ( source runit.sh )jest dobrą odpowiedzią; Nie myślałem o tym. I dobry zbiór referencji.
Scott