Bagaimana cara memanggil satu skrip shell dari skrip shell lain?

739

Saya memiliki dua skrip shell, a.shdan b.sh.

Bagaimana saya bisa menelepon b.shdari dalam skrip shell a.sh?

Praveen
sumber
8
Bisakah Anda memberikan beberapa spesifik: OS mana dan shell mana (s) atau Anda hanya berbicara tentang masalah itu pada prinsipnya ?? Kode contoh akan sangat membantu juga.
jsalonen
14
Ini bukan pertanyaan spesifik dan juga tidak menunjukkan upaya sebelumnya untuk menyelesaikan masalah.
Kris
1
Satu masalah yang saya alami adalah bahwa b.shtidak memiliki izin yang dapat dieksekusi. Mungkin bagus untuk memeriksanya.
seth10
Tambahkan ./sebelum nama skrip, misalnya, sebagai gantinya b.sh./b.sh
Benny
1
Jika ada yang terus mendapatkan No such file or directorykesalahan stackoverflow.com/a/2920431/1356559
Amr Lotfy

Jawaban:

959

Ada beberapa cara berbeda untuk melakukannya:

  1. Jadikan skrip lain dapat dieksekusi, tambahkan #!/bin/bashbaris di atas, dan path tempat file tersebut ke variabel lingkungan $ PATH. Kemudian Anda dapat menyebutnya sebagai perintah normal;

  2. Atau panggil dengan sourceperintah (alias .) seperti ini source /path/to/script:;

  3. Atau gunakan bashperintah untuk melaksanakannya: /bin/bash /path/to/script;

Metode pertama dan ketiga menjalankan skrip sebagai proses lain, sehingga variabel dan fungsi dalam skrip lain tidak akan dapat diakses.
Metode kedua mengeksekusi skrip dalam proses skrip pertama, dan menarik variabel dan fungsi dari skrip lain sehingga mereka dapat digunakan dari skrip panggilan.

Pada metode kedua, jika Anda menggunakan exitskrip kedua, itu juga akan keluar dari skrip pertama. Yang tidak akan terjadi dalam metode pertama dan ketiga.

Beberapa programmer dude
sumber
30
ingat chmod a+x /path/to/fileatau kalau tidak itu tidak akan dapat dieksekusi. Hanya berlaku untuk metode ./script.
Nathan Lilienthal
3
Ingatlah untuk mengubah format / pengodean file yang dapat dieksekusi di unix jika dibuat di DOS dan kemudian diunggah ke lingkungan unix -> dos2unix <nama skrip>
Abhishek Chatterjee
3
@cecemel Cara pertama dan ketiga bisa "async" dengan menggunakan sintaks run-in-background normal.
Beberapa programmer Bung
16
Masalahnya dengan sourceitu adalahexit pernyataan dalam skrip yang dipanggil akan keluar dari Anda juga ...
Ohad Schneider
18
@ user528025 .bukan alias untuk source, melainkan sebaliknya. sourceadalah ekstensi bash, sementara .bekerja di shell POSIX yang kompatibel.
Score_Under
207

Lihat ini.

#!/bin/bash
echo "This script is about to run another script."
sh ./script.sh
echo "This script has just run another script."
Budha
sumber
4
Ini mengasumsikan script.sh berada di direktori yang sama dengan script apa pun yang sedang berjalan. Jika Anda ingin memanggil naskah di tempat lain, Anda bisa mengatakansh <path to script>/script.sh
Morgan Kenyon
32
Ini juga menggunakan dua kerang, bashdan sh. Bahkan ketika shsebenarnya bashitu tidak berperilaku sama. Jika Anda menggunakan #!/bin/bashmaka Anda mungkin ingin menggunakan bash script.sh(atau hanya ./script.shmenggunakan hashbang skrip itu).
Martin Tournoij
1
Terus mendapatkan izin ditolak kesalahan bahkan ketika saya mengatur chmod +xke file .sh. Ada saran?
isaac weathers
@isaacweathers coba chmod 777
Janac Meena
114

Ada beberapa cara Anda bisa melakukan ini. Terminal untuk menjalankan skrip:

#!/bin/bash
SCRIPT_PATH="/path/to/script.sh"

# Here you execute your script
"$SCRIPT_PATH"

# or
. "$SCRIPT_PATH"

# or
source "$SCRIPT_PATH"

# or
bash "$SCRIPT_PATH"

# or
eval '"$SCRIPT_PATH"'

# or
OUTPUT=$("$SCRIPT_PATH")
echo $OUTPUT

# or
OUTPUT=`"$SCRIPT_PATH"`
echo $OUTPUT

# or
("$SCRIPT_PATH")

# or
(exec "$SCRIPT_PATH")

Semua ini benar untuk jalur dengan spasi !!!

Andrei Krasutski
sumber
41
Apa perbedaan mereka? Mengapa satu, mengapa yang lain?
rocketspacer
. "$ SCRIPT_PATH" lebih disukai
Harry Mumford-Turner
1
Saya hanya dapat menambahkan bahwa ini tidak semuanya setara, mis. Sh "$ SCRIPT_PATH" dan bash "$ SCRIPT_PATH" tidak akan menjalankan skrip #! / Usr / bin / expect, sedangkan "$ SCRIPT_PATH" akan.
Tahlor
58

Jawaban yang saya cari:

( exec "path/to/script" )

Seperti yang disebutkan, execmengganti shell tanpa membuat proses baru. Namun , kita bisa memasukkannya ke dalam subkulit, yang dilakukan menggunakan paranthes.

EDIT: Sebenarnya ( "path/to/script" )sudah cukup.

Maxim Chetrusca
sumber
11
Ini sepertinya berbelit-belit. Mengapa tidak menyebutnya saja /path/to/script? Saya tidak melihat perlunya execsama sekali di sini?
Martin Tournoij
Subshell tidak diperlukan juga karena Anda tidak execing.
Karel Vlk
6
bagaimana Anda menjalankan skrip ini dengan argumen?
Bhargav
Jika Anda ingin tetap menangkap output dari sub-skrip, coba $ (sumber "path / ke / skrip")
cmcginty
@Bhargav ikuti tautan ini stackoverflow.com/questions/14302389/…
tpbafk
16

Tergantung pada. Secara singkat ... Jika Anda ingin memuat variabel pada konsol saat ini dan mengeksekusi Anda dapat menggunakan source myshellfile.shkode Anda. Contoh:

!#/bin/bash
set -x
echo "This is an example of run another INTO this session."
source my_lib_of_variables_and_functions.sh
echo "The function internal_function() is defined into my lib."
returned_value=internal_function()
echo $this_is_an_internal_variable

set +x

Jika Anda hanya ingin mengeksekusi file dan satu-satunya hal yang bersinggungan dengan Anda adalah hasilnya, Anda dapat melakukannya:

!#/bin/bash
set -x
./executing_only.sh
sh i_can_execute_this_way_too.sh
bash or_this_way.sh
set +x

Saya harap membantu Anda. Terima kasih.

Douglas Bonafé
sumber
2
Perhatikan bahwa sourceini adalah fitur khusus bash. Shell bourne standar hanya memiliki .(misalnya . other_script.sh).
Martin Tournoij
15

Anda dapat menggunakan /bin/shuntuk memanggil atau menjalankan skrip lain (melalui skrip Anda yang sebenarnya):

 # cat showdate.sh
 #!/bin/bash
 echo "Date is: `date`"

 # cat mainscript.sh
 #!/bin/bash
 echo "You are login as: `whoami`"
 echo "`/bin/sh ./showdate.sh`" # exact path for the script file

Outputnya adalah:

 # ./mainscript.sh
 You are login as: root
 Date is: Thu Oct 17 02:56:36 EDT 2013
Ranjithkumar T
sumber
1
Tentunya ini akan berjalan di showdate.shbawah / bin / sh daripada / bin / bash?
Chris Watts
Saya telah mencoba dengan " /bin/sh ./showdate.sh", " /bin/bash ./showdate.sh", " ./showdate.sh" dan menjalankan file: mainscript.sh dan mendapat hasil yang sama.
Ranjithkumar T
10

Cukup tambahkan baris apa pun yang Anda ketikkan di terminal untuk menjalankan skrip!
misalnya:

#!bin/bash
./myscript.sh &

Jika skrip yang akan dieksekusi tidak berada di direktori yang sama, cukup gunakan path lengkap skrip.
misalnya: `/ home / user / direktori-skrip /./ myscript.sh &

Segera
sumber
@Carpetsmoker &untuk tugas latar belakang
Andrei Krasutski
9

Pertama, Anda harus memasukkan file yang Anda panggil:

#!/bin/bash
. includes/included_file.sh

maka Anda memanggil fungsi Anda seperti ini:

#!/bin/bash
my_called_function
Ghazi Triki
sumber
9

Sumber sederhana akan membantu Anda. Untuk Kel.

#!/bin/bash
echo "My shell_1"
source my_script1.sh
echo "Back in shell_1"
Nitin Jawarkar
sumber
9

Jika Anda memiliki file lain di direktori yang sama, Anda dapat melakukannya:

bash another_script.sh

atau

source another_script.sh

atau

. another_script.sh

Saat Anda menggunakan bashalih-alih source, skrip tidak dapat mengubah lingkungan skrip induk. The .perintah POSIX standar sementara sourceperintah bash sinonim lebih mudah dibaca untuk .(saya lebih suka sourcelebih .). Jika skrip Anda berada di tempat lain, berikan jalur ke skrip itu. Path relatif maupun penuh harus bekerja.

Shital Shah
sumber
5

Jawaban teratas menyarankan menambahkan #!/bin/bashbaris ke baris pertama dari sub-skrip yang dipanggil. Tetapi bahkan jika Anda menambahkan shebang, itu jauh lebih cepat * untuk menjalankan skrip di sub-shell dan menangkap output:

$(source SCRIPT_NAME)

Ini berfungsi ketika Anda ingin tetap menjalankan interpreter yang sama (misalnya dari bash ke skrip bash lain) dan memastikan bahwa garis shebang dari sub-skrip tidak dieksekusi.

Sebagai contoh:

#!/bin/bash
SUB_SCRIPT=$(mktemp)
echo "#!/bin/bash" > $SUB_SCRIPT
echo 'echo $1' >> $SUB_SCRIPT
chmod +x $SUB_SCRIPT
if [[ $1 == "--source" ]]; then
  for X in $(seq 100); do
    MODE=$(source $SUB_SCRIPT "source on")
  done
else
  for X in $(seq 100); do
    MODE=$($SUB_SCRIPT "source off")
  done
fi
echo $MODE
rm $SUB_SCRIPT

Keluaran:

~ ❯❯❯ time ./test.sh
source off
./test.sh  0.15s user 0.16s system 87% cpu 0.360 total

~ ❯❯❯ time ./test.sh --source
source on
./test.sh --source  0.05s user 0.06s system 95% cpu 0.114 total

* Misalnya ketika virus atau alat keamanan sedang berjalan di perangkat, mungkin dibutuhkan 100 ms tambahan untuk menjalankan proses baru.

cmcginty
sumber
4
pathToShell="/home/praveen/"   
chmod a+x $pathToShell"myShell.sh"
sh $pathToShell"myShell.sh"
Abdennour TOUMI
sumber
4
 #!/bin/bash

 # Here you define the absolute path of your script

 scriptPath="/home/user/pathScript/"

 # Name of your script

 scriptName="myscript.sh"

 # Here you execute your script

 $scriptPath/$scriptName

 # Result of script execution

 result=$?
Valero
sumber
1
salah untuk folder scriptPathatau nama file scriptNamedengan spasi
Andrei Krasutski
3

Asumsikan file baru adalah "/ home / satya / app / app_specific_env" dan konten file adalah sebagai berikut

#!bin/bash

export FAV_NUMBER="2211"

Tambahkan referensi file ini ke file ~ / .bashrc

source /home/satya/app/app_specific_env

Ketika Anda menghidupkan ulang mesin atau login kembali, coba echo $FAV_NUMBERdi terminal. Ini akan menampilkan nilai.

Untuk jaga-jaga jika Anda ingin melihat efeknya segera, source ~/.bashrcdi baris perintah.

Satya Kalluri
sumber
3
chmod a+x /path/to/file-to-be-executed

Itulah satu-satunya yang saya butuhkan. Setelah skrip yang akan dieksekusi dibuat dapat dieksekusi seperti ini, Anda (setidaknya dalam kasus saya) tidak memerlukan operasi tambahan seperti shatau./ saat Anda memanggil skrip.

Terima kasih atas komentar @Nathan Lilienthal

Asqan
sumber
1

Ada beberapa masalah untuk mengimpor fungsi dari file lain.
Pertama : Anda tidak perlu melakukan file ini dapat dieksekusi. Lebih baik tidak melakukannya! tambahkan saja

. file

untuk mengimpor semua fungsi. Dan semuanya akan seolah-olah didefinisikan dalam file Anda.
Kedua : Anda mungkin mendefinisikan fungsi dengan nama yang sama. Itu akan ditimpa. Itu buruk. Anda dapat mendeklarasikan seperti itu

declare -f new_function_name=old_function_name 

dan hanya setelah itu impor. Jadi, Anda dapat memanggil fungsi lama dengan nama baru.
Ketiga : Anda hanya dapat mengimpor daftar lengkap fungsi yang ditentukan dalam file. Jika beberapa tidak diperlukan, Anda dapat menghapusnya. Tetapi jika Anda menulis ulang fungsi Anda setelah tidak disetel mereka akan hilang. Tetapi jika Anda menetapkan referensi seperti yang dijelaskan di atas, Anda dapat memulihkan setelah tidak disetel dengan nama yang sama.
AkhirnyaSecara umum prosedur impor berbahaya dan tidak begitu sederhana. Hati-hati! Anda dapat menulis skrip untuk melakukan ini lebih mudah dan aman. Jika Anda hanya menggunakan sebagian fungsi (tidak semua) lebih baik membaginya dalam file yang berbeda. Sayangnya teknik ini tidak dibuat dengan baik di bash. Dalam python misalnya dan beberapa bahasa skrip lainnya mudah dan aman. Kemungkinan untuk melakukan impor parsial hanya fungsi-fungsi yang diperlukan dengan namanya sendiri. Kita semua ingin bahwa dalam versi semak berikutnya akan dilakukan fungsi yang sama. Tetapi sekarang, kita harus menulis banyak cod tambahan untuk melakukan apa yang Anda inginkan.

Anatoly
sumber
(Selamat datang di SO!) Karena pengguna Praveen terakhir kali terlihat pada tahun 2011, pasti akan sulit untuk memilah apakah pertanyaannya adalah bagaimana membuat shell mengeksekusi a.sh mengeksekusi b.sh (dan melanjutkan menjalankan a.sh jika tidak diperintahkan sebaliknya ), atau untuk secara harfiah memanggil bsh . (Saya ejaan tidak menangkap bush versions.) (Apakah Anda memiliki seseorang untuk beralih ke untuk membantu Anda dengan tata bahasa Inggris (Kadang-kadang berharap aku punya)?.)
orangtua
0

Gunakan backticks.

$ ./script-that-consumes-argument.sh `sh script-that-produces-argument.sh`

Kemudian ambil output dari skrip produser sebagai argumen pada skrip konsumen.

dacabdi
sumber