Mengapa saya tidak dapat memuat modul saat menjalankan skrip bash saya, tetapi hanya saat mengambilnya?

12

Saya menggunakan modul untuk mengontrol paket-paket di sistem saya dan saya telah python/2.7.2menginstal sebagai modul. Saya memiliki executable python sederhana python_exe.pyyang akan saya panggil dari skrip 'mengemudi' sederhana runit.sh. runit.shskrip terlihat seperti:

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

Namun, ketika saya baru saja menjalankan ./runit.sh, itu menjual saya "module: command not found". Ketika saya source runit.sh, bagaimanapun, itu memuat modul dengan benar. Kenapa ini?

drjrm3
sumber

Jawaban:

13

Karena moduleperintahnya adalah fungsi alias atau shell (lihat " Paket Inisialisasi " dalam modul (1) ). Ketika Anda berkata source runit.sh, itu seperti mengetik moduleperintah langsung ke shell interaktif Anda. Tetapi ketika Anda mengatakan ./runit.sh, Anda menjalankan shell baru, non-interaktif. Kerang non-interaktif umumnya tidak memiliki alias standar dan fungsi shell diatur.

module (1) mengatakan, “Paket Modul dan perintah modul diinisialisasi ketika skrip inisialisasi spesifik-shell dimasukkan ke dalam shell. Skrip menciptakan perintah modul , baik sebagai fungsi alias atau fungsi shell, ... ”Jika Anda perlu menjalankan moduleperintah dalam skrip, temukan skrip inisialisasi yang menentukan moduleperintah dan sourcedari skrip.

Scott
sumber
Apakah ini perbedaan antara menggunakan .bashrc dan .bash_profile? Hanya satu dari mereka yang memiliki rutin inisialisasi untuk memulai sistem modul untuk digunakan.
drjrm3
Saya tidak yakin apa yang Anda tanyakan. Tetapi: bash melakukan hal berikut secara default (tindakan ini dapat diganti dengan opsi): shell login bertuliskan `~ / .bash_profile` tetapi tidak ~/.bashrc, shell interaktif yang bukan shell login (mis. Apa yang Anda dapatkan jika Anda mengetikkan bashsebagai a perintah) membaca ~/.bashrctetapi tidak ~/.bash_profile, dan shell non-interaktif (misalnya, satu menjalankan skrip) tidak membaca. … (Lanjutan)
Scott
(Lanjutan) ... Ini mungkin mengapa Cyrus menyarankan #!/bin/bash -i- karena -iopsi membuat shell interaktif, dan karena itu akan membuatnya membaca ~/.bashrc. IMHO, itu berlebihan, karena mode interaktif mungkin datang dengan bagasi yang tidak diinginkan (seperti menulis ke ~/.bash_history). Di sisi lain, jika moduledidefinisikan sebagai alias (sebagai lawan dari fungsi shell), itu tidak akan berfungsi dalam shell non-interaktif kecuali jika Anda mengatakannya shopt -s expand_aliases, jadi mungkin jawaban Cyrus adalah yang terbaik.
Scott
4

Tampaknya permohonan sederhana shell di sistem Anda tidak mewarisi alias (atau fungsi) yang didefinisikan module, sehingga shell tidak dapat menemukannya (lihat catatan di bawah dengan kutipan). Coba type moduledari prompt untuk melihat bagaimana moduledefinisi saat ini.

Intinya dengan sumber seperti jika Anda menulis setiap baris skrip dari keyboard.
Perhatikan bahwa di satu sisi Anda mewarisi semua riwayat spesifik shell saat ini tetapi, di sisi lain, shell saat ini akan mengalami semua efek sisi skrip dan moduledoa Anda.

Tentang perbedaan antara sumber skrip dan menjalankannya Anda dapat membaca di SuperUser Sep 2009 atau Des 2009 , Ubuntu Februari 2011 , Unix Agu 2011 , Stackoverflow Desember 2012 atau di banyak tempat lain.

Dalam hal ini di Modulefiles bagian ada peringatan :

... Variabel lingkungan tidak disetel saat membongkar modulefile. Dengan demikian, adalah mungkin untuk memuat modulefile dan kemudian membongkar tanpa variabel lingkungan kembali ke keadaan semula .

Jadi sepertinya lebih bijak untuk mengeksekusinya dalam naskah .

Untuk mencapai yang terakhir ini saya bisa berpikir:

  1. Untuk menggunakan shell interaktif , abaikan riwayat spesifik shell saat ini, dengan memodifikasi shebang skrip Anda

    #!/bin/bash -i

    Shell interaktif membaca perintah dari input pengguna pada tty. Antara lain, shell tersebut membaca file startup saat aktivasi, menampilkan prompt, dan mengaktifkan kontrol pekerjaan secara default ...

  2. Jika Anda lebih suka mewarisi cerita spesifik dari shell ini, Anda dapat mencoba untuk sumbernya ... tetapi dalam subkulit

    ( source runit.sh )
  3. Cobalah untuk menemukan alias / fungsi saat ini moduledengan type modulekemudian memodifikasi skrip Anda. Perhatikan beberapa variabel lingkungan tidak dapat diatur module.
    Jika mau, Anda dapat menemukan skrip inisialisasi di direktori $MODULESHOME/init/<shell>.


Komentar
Seperti yang diingat dalam Tanya Jawab modul

Proses anak (skrip) tidak dapat mengubah lingkungan proses induk. Memuat modul dalam skrip hanya memengaruhi lingkungan skrip itu sendiri. Satu-satunya cara Anda dapat membuat skrip mengubah lingkungan saat ini adalah dengan sumber skrip yang membacanya ke dalam proses saat ini.

Jadi jika Anda ingin menghindari memodifikasi lingkungan saat ini saya pikir lebih baik untuk mencoba mengubah shebang (1) atau sumber skrip dalam subshell (2). Saya tidak sepenuhnya yakin tentang kegunaan kasus ini (3).


Catatan
Kutipan dari halaman manual dan deskripsi modul

moduleadalah antarmuka pengguna ke paket Modul. The modulealias atau fungsi mengeksekusi modulecmdprogram serta memiliki shell mengevaluasi output perintah ini. Argumen pertama yang modulecmdmenentukan jenis shell.

Paket Modul dan moduleperintah diinisialisasi ketika skrip inisialisasi spesifik-shell bersumber ke dalam shell . Script menciptakan perintah modul, baik sebagai fungsi alias atau shell, membuat variabel lingkungan Modul

Cepat
sumber
Tetapi dia tidak mencoba untuk mempengaruhi lingkungan dari proses induk; dia hanya berusaha agar Python-nya dapat dijalankan dari skrip . Selain itu, jawaban Anda tidak menjelaskan mengapa ia mendapat pesan kesalahan "modul: command not found".
Scott
@Scott Terima kasih. Sebelumnya saya secara tidak sengaja memotong bagian terbesar dari jawaban dan hanya memposting sebagian saja. Jawaban ditulis ulang.
Hastur
1
+1.  ( source runit.sh )adalah jawaban yang bagus; Saya belum memikirkannya. Dan koleksi referensi yang bagus.
Scott