bashスクリプトの実行中にモジュールを読み込むことができないのはなぜですか?


12

モジュールを使用してシステム上のパッケージを制御python/2.7.2し、モジュールとしてインストールしました。単純なpython実行可能ファイルがpython_exe.pyあり、これを単純な「駆動」スクリプトから呼び出しますrunit.shrunit.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ただし、Iの場合、モジュールは正しくロードされます。どうしてこれなの?

回答:


13

ためmoduleのコマンドは、エイリアスまたはシェル関数である(「参照パッケージの初期化に」 モジュール(1) )。と言うときはsource runit.shmodule対話型シェルにコマンドを直接入力するようなものです。ただし、と言う./runit.shときは、新しい非対話型のシェルを実行しています。通常、非対話型シェルには、標準のエイリアスとシェル関数が設定されていません。

module(1)は、「シェル固有の初期化スクリプトがシェルにソースされると、Modulesパッケージとmoduleコマンドが初期化されます。スクリプトは、モジュールコマンドをエイリアスまたはシェル関数として作成します …」moduleスクリプトでコマンドを実行する必要がある場合は、スクリプトからmoduleコマンドとsourceそれを定義する初期化スクリプトを見つけます。


これは、.bashrcと.bash_profileの使用の違いですか?そのうちの1つだけが、使用するモジュールシステムを起動するための初期化ルーチンを持っています。
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. modulewithの現在のエイリアス/関数を見つけてtype module、結果としてスクリプトを修正してください。一部の環境変数はに設定できないことに注意してくださいmodule
    必要に応じて、ディレクトリで初期化スクリプトを見つけることができます$MODULESHOME/init/<shell>


コメントモジュールのQ&Aで
記憶されているとおり

子プロセス(スクリプト)は親プロセス環境を変更できません。スクリプト内のモジュールのロードは、スクリプト自体の環境にのみ影響します。スクリプトで現在の環境を変更できる唯一の方法は、スクリプトを読み込んで現在のプロセスに読み込むことです。

したがって、現在の環境の変更を避けたい場合は、シバンを変更するか(1)、またはサブシェルでスクリプトをソースする(2)ことをお勧めします。case(3)の使いやすさについては完全にはわかりません。


ノート
のマニュアルや説明のページから抜粋モジュール

moduleモジュールパッケージへのユーザーインターフェイスです。moduleエイリアスや関数が実行しmodulecmdたプログラムを、シェルがコマンドの出力を評価しています。の最初の引数modulecmdは、シェルのタイプを指定します。

Modulesパッケージとmoduleコマンドは、シェル固有の初期化スクリプトがシェルにソースされると初期化されます。このスクリプトは、エイリアスまたはシェル関数としてモジュールコマンドを作成し、Modules環境変数を作成します


しかし、彼は親プロセスの環境に影響を与えようとはしていません。彼はPython実行可能ファイルをスクリプトから実行しようとしているだけです。その上、あなたの答えは彼が「モジュール:コマンドが見つかりません」というエラーメッセージを受け取る理由を説明していません。
スコット

@スコットありがとう。答えの大部分をうっかり切り取って、断片だけを投稿する前に。回答を書き直しました。
ハスター

1
+1。  ( source runit.sh )良い答えです。私はそれを考えていませんでした。そして、参考文献の良いコレクション。
スコット
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.