Berbagai cara untuk menjalankan skrip shell

44

Ada beberapa cara untuk menjalankan skrip, yang saya tahu adalah:

/path/to/script # using the path (absolute or relative)
. script        # using the . (dot)
source script   # using the `source` command

Apakah lebih dari ini? Apa perbedaan di antara mereka? Apakah ada situasi yang harus saya gunakan satu dan bukan yang lain?

phhehehe
sumber
Senang mengetahui, terima kasih atas pertanyaan dan jawaban Anda di bawah ini, terutama pertanyaan Shawn. Saya ingin menambahkan sesuatu yang tidak terlalu jelas bagi saya sampai saya menjalankan beberapa tes. Dimasukkannya "/" dengan cara kedua di atas akan membawa perintah ke mode 1 di atas. Yaitu, ketika "./myscript.sh" mengikuti mode 1, ". Myscript.sh" tetap pada mode 2. Anda memang menyebutkan "menggunakan jalur (absolut atau relatif)", tetapi hanya ingin membuat ini tampak jelas.
Arun

Jawaban:

32

Cara lain adalah dengan memanggil juru bahasa dan meneruskan path ke skrip untuk itu:

/bin/sh /path/to/script

Titik dan sumbernya setara. (EDIT: tidak, mereka tidak: seperti yang ditunjukkan KeithB dalam komentar atas jawaban lain, "." Hanya bekerja di shell terkait bash, di mana "source" bekerja di shell terkait bash dan csh.) Ia menjalankan skrip di -place (seolah-olah Anda menyalin dan menempelkan skrip di sana). Ini berarti bahwa setiap fungsi dan variabel non-lokal dalam skrip tetap ada. Ini juga berarti jika skrip melakukan cd ke direktori, Anda akan tetap berada di sana ketika selesai.

Cara lain menjalankan skrip akan menjalankannya dalam subkulitnya sendiri. Variabel dalam skrip tidak masih hidup saat selesai. Jika skrip mengubah direktori, maka skrip tidak memengaruhi lingkungan panggilan.

/ path / to / script dan / bin / sh script sedikit berbeda. Biasanya, sebuah skrip memiliki "shebang" di awal yang terlihat seperti ini:

#! /bin/bash

Ini adalah jalan menuju juru bahasa skrip. Jika ia menentukan juru bahasa yang berbeda dari yang Anda lakukan ketika Anda menjalankannya, maka itu mungkin berperilaku berbeda (atau mungkin tidak bekerja sama sekali).

Misalnya, skrip Perl dan skrip Ruby dimulai dengan (masing-masing):

#! /bin/perl

dan

#! /bin/ruby

Jika Anda menjalankan salah satu skrip tersebut dengan menjalankan /bin/sh script, maka skrip tersebut tidak akan berfungsi sama sekali.

Ubuntu sebenarnya tidak menggunakan bash shell, tetapi yang sangat mirip disebut dasbor. Skrip yang memerlukan bash mungkin berfungsi sedikit salah ketika dipanggil dengan melakukan /bin/sh scriptkarena Anda baru saja memanggil skrip bash menggunakan penerjemah dasbor.

Perbedaan kecil lainnya antara memanggil skrip secara langsung dan meneruskan path skrip ke penerjemah adalah skrip harus ditandai dapat dieksekusi untuk menjalankannya secara langsung, tetapi tidak menjalankannya dengan meneruskan path ke interpreter.

Variasi kecil lainnya: Anda dapat mengawali salah satu cara ini untuk menjalankan skrip dengan eval, jadi, Anda dapat memilikinya

eval sh script
eval script
eval . script

dan seterusnya. Sebenarnya tidak mengubah apa pun, tapi saya pikir saya akan memasukkannya untuk ketelitian.

Shawn J. Goff
sumber
6
Mengatakan "Ubuntu sebenarnya tidak menggunakan bash shell" tidak tepat dan secara teknis salah. Ubuntu memang menggunakan bash shell, intinya adalah yang shberhubungan dengan dash, tetapi tidak untuk bash.
Faheem Mitha
@Shawn Di pertama para Anda menulis "Ini mengeksekusi skrip di tempat (seolah-olah Anda menyalin dan menempelkan skrip di sana). Ini berarti bahwa setiap fungsi dan variabel non-lokal dalam skrip tetap ada." apa maksudmu dengan baris kedua di sini? Tolong jelaskan.
Geek
@Geek ketika Anda menjalankan skrip sebagai proses anak (cara normal), setiap variabel dan fungsi yang didefinisikannya (lingkungannya) hilang ketika proses berakhir. Jika Anda sumber skrip, variabel dan fungsi tersebut dibuat di lingkungan saat ini; ketika skrip selesai, perubahan pada lingkungan tetap ada.
Shawn J. Goff
@ ShawnJ.Goff terima kasih atas klarifikasi. +1.
Geek
Plot-twist: Bourne Shell (sh) hanya menerima titik - bukan sumber karena merupakan bash-builtin. pubs.opengroup.org/onlinepubs/9699919799/utilities/... Jadi menurut saya cara yang paling portabel adalah titik.
dezza
9

Kebanyakan orang men-debug skrip shell dengan menambahkan flag debuging berikut ke skrip:

set -x     # Print command traces before executing command.
set -v     # Prints shell input lines as they are read.
set -xv    # Or do both

Tapi ini berarti Anda harus membuka file dengan editor (dengan asumsi Anda memiliki izin untuk mengedit file), menambahkan baris seperti set -x, menyimpan file, lalu jalankan file. Kemudian ketika Anda selesai, Anda harus mengikuti langkah-langkah yang sama dan menghapus set -x, dll. Ini bisa membosankan.

Alih-alih melakukan semua itu, Anda dapat mengatur bendera debug pada baris perintah:

$ bash -x ~/bin/ducks
+ du -cks -x dir1 dir2 dir3 file1 file2 file3
+ sort -n
+ tail .ducks
123 etc
424 bin
796 total



$ sh -xv ~/bin/ducks  
#!/usr/bin/env bash

# Find the disk hog
# Borrowed from http://oreilly.com/pub/h/15
...
...
Stefan Lasiewski
sumber
2
Kiat terkait: Saya sudah terbiasa meletakkan emulate sh 2>/dev/nulldi bagian atas skrip shell saya. Saat dijalankan dengan zsh, ini membuatnya menjadi mode yang kompatibel dengan POSIX. Ketika dijalankan dengan cangkang lain, garis tidak memiliki efek. Maka saya dapat menjalankan skrip dengan zsh -x /path/to/script. Saya suka zsh di sini karena menyediakan jejak yang lebih baik daripada bash atau ksh.
Gilles 'SO- stop being evil'
7

Shawn J. Goff membuat banyak poin bagus, tetapi tidak memasukkan keseluruhan cerita:

Ubuntu sebenarnya tidak menggunakan bash shell, tetapi yang sangat mirip disebut dasbor. Skrip yang memerlukan bash mungkin berfungsi sedikit salah ketika dipanggil dengan melakukan /bin/shskrip karena Anda baru saja memanggil skrip bash menggunakan penerjemah dasbor.

Banyak skrip sistem (seperti di init.d, di / etc dan sebagainya) memiliki shebang #!/bin/sh, tetapi /bin/shsebenarnya merupakan tautan simbolis ke shell lain - di masa lalu /bin/bash, saat ini /bin/dash. Tetapi ketika salah satu dari mereka dipanggil sebagai /bin/sh, mereka berperilaku berbeda, yaitu mereka tetap pada mode kompatibilitas-POSIX.

bagaimana mereka melakukan ini? Yah, mereka memeriksa bagaimana mereka dipanggil.

Bisakah shellscript itu sendiri menguji bagaimana itu dipanggil, dan melakukan hal-hal yang berbeda, tergantung pada itu? Ya bisa. Jadi cara Anda memintanya selalu dapat menyebabkan hasil yang berbeda, tetapi tentu saja itu jarang dilakukan untuk mengganggu Anda. :)

Sebagai aturan praktis: Jika Anda mempelajari shell tertentu seperti bash, dan menulis perintah dari tutorial bash, masukkan #!/bin/bashinformasi utama, bukan #!/bin/sh, kecuali jika disebutkan sebaliknya. Jika tidak, perintah Anda mungkin gagal. Dan jika Anda belum menulis skrip sendiri, jalankan secara langsung ( ./foo.sh, bar/foo.sh) alih-alih menebak sebuah shell ( sh foo.sh, sh bar/foo.sh). Shebang harus memanggil shell yang tepat.

Dan inilah dua jenis doa lainnya:

cat foo.sh | dash
dash < foo.sh
Pengguna tidak diketahui
sumber
5

.dan sourcesetara karena mereka tidak menelurkan subproses tetapi menjalankan perintah dalam shell saat ini. Ini penting ketika skrip mengatur variabel lingkungan atau mengubah direktori kerja saat ini.

Menggunakan jalur atau memberikannya untuk /bin/shmembuat proses baru di mana perintah dijalankan.

mouviciel
sumber
2
sh script
bash script

Saya merenungkan jika ada lebih banyak ...

.dan sourcesama. Setelah eksekusi, setiap perubahan lingkungan scriptakan disimpan. Biasanya, ini akan digunakan untuk sumber perpustakaan Bash, sehingga perpustakaan dapat digunakan kembali dalam banyak skrip yang berbeda.

Juga cara yang baik untuk menyimpan direktori saat ini. Jika Anda mengubah direktori dalam skrip, itu tidak akan diterapkan di shell yang Anda jalankan skrip itu. Tetapi jika Anda sumber untuk menjalankannya, setelah skrip keluar, direktori saat ini akan disimpan.

livibetter
sumber
2
.hanya berfungsi di sh / bash dan shell terkait. sourcejuga bekerja di csh dan cangkang terkait.
KeithB
1

Apakah " userland exec " dihitung sebagai cara yang berbeda? Exec Userland memuat kode dan menjalankannya tanpa menggunakan panggilan sistem execve ().

Bruce Ediger
sumber
1
. ./filename
# ( dot space dot slash filename )

Menjalankan skrip di shell saat ini ketika direktori tidak di jalan.

Stefan
sumber
1

. dan sumber sedikit berbeda di zsh setidaknya (itulah yang saya gunakan) karena

source file

Bekerja, sementara

. file

tidak, itu perlu

. ./file
bollovan
sumber