Warum kann ich keine Module laden, während ich mein Bash-Skript ausführe, sondern nur, wenn ich es beziehe?

12

Ich verwende Module zur Steuerung der Pakete auf meinem System und habe python/2.7.2sie als Modul installiert. Ich habe eine einfache ausführbare Python-Datei, python_exe.pydie ich von einem einfachen "Fahr" -Skript aufrufen werde runit.sh. runit.shDas Skript sieht ungefähr so ​​aus:

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

Wenn ich gerade starte, wird ./runit.shmir jedoch "module: command not found" verkauft. Wenn ich source runit.shdas Modul jedoch richtig lade. Warum ist das?

drjrm3
quelle

Antworten:

13

Weil der moduleBefehl ein Alias ​​oder eine Shell-Funktion ist (siehe " Paketinitialisierung " in Modul (1) ). Wenn Sie sagen source runit.sh, ist es so , als würden Sie den moduleBefehl direkt in Ihre interaktive Shell eingeben . Aber wenn Sie sagen ./runit.sh, dass Sie eine neue, nicht interaktive Shell ausführen. Bei nicht interaktiven Shells sind im Allgemeinen nicht die Standardaliase und -shellfunktionen eingerichtet.

In module (1) heißt es: „Das Modulpaket und der Modulbefehl werden initialisiert, wenn ein Shell-spezifisches Initialisierungsskript in die Shell eingespeist wird. Das Skript erstellt den Modulbefehl entweder als Alias ​​oder als Shell-Funktion. Wenn Sie den moduleBefehl in einem Skript ausführen müssen , suchen Sie das Initialisierungsskript, das den moduleBefehl definiert, und sourcedas Skript.

Scott
quelle
Ist dies der Unterschied zwischen der Verwendung von .bashrc und .bash_profile? Nur einer von ihnen verfügt über die Initialisierungsroutinen, um das Modulsystem zur Verwendung hochzufahren.
Drjrm3
Ich bin mir nicht ganz sicher, wonach du fragst. Aber: bash macht standardmäßig Folgendes (diese Aktionen können durch Optionen überschrieben werden): Eine Login-Shell liest "~ / .bash_profile", aber nicht ~/.bashrceine interaktive Shell, die keine Login-Shell ist (z. B. was Sie erhalten, wenn Sie bashals eingeben) Ein Befehl liest, ~/.bashrcaber nicht ~/.bash_profile, und eine nicht interaktive Shell (z. B. eine, die ein Skript ausführt) liest keine. … (Fortsetzung)
Scott
(Fortsetzung)… Dies ist wahrscheinlich der Grund, warum Cyrus vorgeschlagen hat #!/bin/bash -i- weil die -iOption die Shell interaktiv macht und sie daher zum Lesen veranlasst ~/.bashrc. IMHO, das ist übertrieben, denn der interaktive Modus kann mit unerwünschtem Gepäck einhergehen (wie das Schreiben an ~/.bash_history). Auf der anderen Seite, wenn modulees als Alias ​​definiert ist (im Gegensatz zu einer Shell-Funktion), funktioniert es in einer nicht interaktiven Shell nur, wenn Sie sagen shopt -s expand_aliases, vielleicht ist Cyrus die beste Antwort.
Scott
4

Es scheint, dass der einfache Aufruf der Shell in Ihrem System nicht den Alias ​​(oder die Funktion) erbt, mit dem bzw. der moduledie Shell definiert ist , so dass die Shell ihn nicht finden kann (siehe unten den Hinweis mit den Auszügen). Versuchen Sie type modulean der Eingabeaufforderung zu sehen, wie modulees derzeit definiert ist.

Im Wesentlichen mit Quelle ist wie, wenn Sie jede Zeile des Skripts über die Tastatur schreiben.
Beachten Sie, dass Sie auf der einen Seite den gesamten Verlauf der aktuellen Shell erben, auf der anderen Seite jedoch alle Seiten Ihres Skripts und Ihres Aufrufs auf die aktuelle Shell moduleeinwirken.

Über die Unterschiede zwischen einem Skript zu beziehen und ihn auszuführen Sie auf Super - User lesen September 2009 oder Dezember 2009 , Ubuntu Februar 2011 , Unix August 2011 , Stackoverflow Dezember 2012 oder in vielen anderen Orten.

In diesem Zusammenhang gibt es im Abschnitt Modulefiles eine Warnung :

... Umgebungsvariablen werden beim Entladen einer Moduldatei nicht gesetzt. Auf diese Weise ist es möglich, ein Moduldatei zu laden und dann zu entladen, ohne dass die Umgebungsvariablen in ihren vorherigen Zustand zurückkehren.

Es erscheint daher sinnvoller, es in einem Skript auszuführen .

Um Letzteres zu erreichen, kann ich denken:

  1. Um eine interaktive Shell zu verwenden , vernachlässigen Sie den spezifischen Verlauf der aktuellen Shell und ändern Sie den Shebang Ihres Skripts mit

    #!/bin/bash -i

    Eine interaktive Shell liest Befehle von Benutzereingaben auf einem tty. Unter anderem liest eine solche Shell beim Aktivieren Startdateien, zeigt eine Eingabeaufforderung an und aktiviert standardmäßig die Auftragssteuerung ...

  2. Wenn Sie stattdessen lieber die spezifische Geschichte der vorliegenden Shell erben möchten, können Sie versuchen, sie als Quelle zu verwenden ... aber in einer Subshell

    ( source runit.sh )
  3. Versuchen Sie, den aktuellen Alias ​​/ die aktuelle Funktion von modulemit zu finden, type moduleund ändern Sie anschließend Ihr Skript. Beachten Sie, dass einige Umgebungsvariablen nicht festgelegt werden können module.
    Wenn Sie möchten, finden Sie die Initialisierungsskripte im Verzeichnis $MODULESHOME/init/<shell>.


Kommentar
Wie in der Erinnerung Q & A von Modulen

Ein untergeordneter Prozess (Skript) kann die übergeordnete Prozessumgebung nicht ändern. Eine Modulladung in einem Skript wirkt sich nur auf die Umgebung für das Skript selbst aus. Die einzige Möglichkeit, die aktuelle Umgebung durch ein Skript ändern zu lassen, besteht darin, das Skript als Quelle zu verwenden, das es in den aktuellen Prozess einliest.

Wenn Sie also vermeiden möchten, die aktuelle Umgebung zu ändern, ist es meines Erachtens besser, den shebang (1) zu ändern oder das Skript in einer Subshell (2) zu veröffentlichen. Ich bin mir über die Verwendbarkeit des Falls nicht ganz sicher (3).


Hinweis
Auszüge aus Handbuch- und Beschreibungsseiten von Modulen

moduleist eine Benutzeroberfläche für das Modulpaket. Der moduleAlias ​​oder die Funktion führt das modulecmdProgramm aus und veranlasst die Shell, die Ausgabe des Befehls auszuwerten. Das erste Argument, modulecmddas den Typ der Shell angibt.

Das Modulpaket und der moduleBefehl werden initialisiert, wenn ein Shell-spezifisches Initialisierungsskript in die Shell aufgenommen wird . Das Skript erstellt den Modulbefehl als Alias- oder Shell-Funktion und erstellt Modulumgebungsvariablen

Hastur
quelle
Er versucht jedoch nicht, die Umgebung des übergeordneten Prozesses zu beeinflussen. Er versucht nur, seine ausführbare Python-Datei vom Skript auszuführen . Außerdem erklärt Ihre Antwort nicht, warum er die Fehlermeldung "module: command not found" erhält.
Scott
@ Scott Danke. Vorher habe ich versehentlich den größten Teil der Antwort abgeschnitten und nur ein Fragment gepostet. Antwort neu geschrieben.
Hastur
1
+1.  ( source runit.sh )ist eine gute Antwort; Ich hatte nicht daran gedacht. Und eine gute Sammlung von Referenzen.
Scott