Memanggil skrip dengan ./bla.sh vs. bla.sh

11

Adakah yang bisa menjelaskan kepada saya apa yang dilakukan shell pada dua contoh A) dan B) di bawah ini? Ini jelas berperilaku berbeda, tetapi saya tidak bisa mencari tahu mengapa outputnya berbeda.

Contoh:
Mari kita memiliki skrip di direktori kami saat ini bernama bla.shdengan hanya satu perintah:
echo ${0##/*} hello

A)
Dimulai sebagai: ./bla.sh
memberi:./bla.sh hello

B)
Dimulai sebagai: . bla.sh
memberi:-bash hello

Karena saya menggunakan ini dalam skrip, output kedua (karena "-" di depan-bash) membunuh perintah. Tentu saja, yang sederhana --sebelum ${...}membantu, tetapi saya ingin memahami apa yang menyebabkan output di tempat pertama.
Saya suka bash. Dan vi [m]. Tapi saya ngelantur ...

Serigala
sumber

Jawaban:

22
./bla.sh

Di sini, perintahnya adalah ./bla.sh. Ini membuat shell mencari executable yang bernama bla.shdalam direktori saat ini, kemudian meminta kernel untuk menjalankannya sebagai program normal, dalam proses terpisah dari shell. (Tidak masalah jika bla.shadalah bashnaskah, seorang perlatau pythonsatu, atau biner disusun.)


. bla.sh

Di sini, perintahnya adalah .(alias source), perintah bawaan dari shell Anda. Itu membuat shell mencari file bernama bla.shdi jalur sistem ($ PATH) dan menafsirkan konten seolah-olah mereka diketik oleh Anda; semua ini dilakukan dalam proses yang sama dengan shell itu sendiri (dan karena itu dapat mempengaruhi keadaan internal shell).

Ini tentu saja hanya berfungsi ketika bla.shberisi perintah untuk bashshell (jika itu yang sedang Anda gunakan), itu tidak akan berfungsi untuk perlskrip atau apa pun.

(Hal ini dijelaskan dalam help .dan help sourcejuga.)


Sebagai .dan ./hal-hal yang sangat berbeda (perintah vs bagian dari jalur), mereka dapat dikombinasikan, tentu saja - menggunakan . ./bla.shakan "sumber" file bla.shdalam direktori saat ini.


Biasanya yang terbaik adalah menggunakan ./bla.shmetode ini. Hanya saja ~/.bashrc, ~/.profiledan file-file tersebut biasanya bersumber, karena mereka diharapkan untuk mengubah lingkungan saat ini.

pengguna1686
sumber
3
Selain itu, jika Anda mengubah lingkungan bash di bla.sh, perubahan ini diperhitungkan setelahnya. bla.sh tetapi tidak setelah ./bla.sh. hal ini karena . bla.sh berjalan dalam konteks bash saat ini sedangkan ./bla.sh berjalan sebagai subproses.
mouviciel
1
Lihat juga mywiki.wooledge.org/BashFAQ/060 untuk beberapa contoh. Perhatikan bahwa sourceini adalah alias bash untuk ., bukan sebaliknya dan sourcetidak akan berfungsi di shell lain.
mrucci
7

./<cmd>akan menjalankan <cmd>program yang berada di direktori saat ini dalam proses baru (bercabang). Itu harus dapat dieksekusi. Dan juga dapat dibaca itu dimulai dengan #!.

. <cmd>akan membuat shell Anda saat ini menjalankan skrip shell <cmd>yang berada di $PATHdirektori Anda atau saat ini dalam proses shell saat ini . Itu harus dibaca. Ini adalah alias untuk perintah shell source.

kmkaplan
sumber
-1 . <cmd>akan mencari program di $PATHdan jika tidak ditemukan maka akan melihat di direktori saat ini.
dogbane
@ benar sopan, saya mengoreksi ini.
kmkaplan
FWIW, tidak semua cangkang akan mencari cwd untuk srip bersumber. zsh (setidaknya dengan konfigurasi yang saya miliki) membutuhkan. ./cmd
bstpierre
1
@ bstpierre Ini sepertinya tempat yang bergerak. Referensi POSIX yang saya katakan bahwa "shell akan menggunakan jalur pencarian yang ditentukan oleh PATH" dan "Beberapa implementasi yang lebih tua mencari direktori saat ini untuk file tersebut, bahkan jika nilai PATH tidak mengizinkannya."
kmkaplan
1

./cmd menggunakan jalur eksplisit ( ./- dir saat ini) ke executable. Dan itu tidak perlu dimulai #!.

. cmd- (alias source) - perintah bash builtin. Satu perbedaan yang terlihat dari mengeksekusi melalui sourceitu dapat mengatur / memodifikasi variabel lingkungan shell saat ini.

Leonid Volnitsky
sumber
lebih tepatnya, sourceadalah bash-only alias to .(yang standar)
user1686
Kamu benar. Tetap.
Leonid Volnitsky