Apa perbedaan antara "sumber x", ". x "dan" ./x "di Bash?

11

Saya punya satu sumber bash run.shsebagai berikut,

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

ketika saya menjalankannya dengan dua cara, ada perilaku yang berbeda. Cara pertama adalah,

source run.sh

Ini akan menutup terminal setelah eksekusi. Cara kedua adalah,

./run.sh

ini hanya akan selesai menjalankan skrip, dan tetap di terminal. Saya bertanya apakah ada perintah untuk keluar dari skrip bash untuk keduanya source run.shdan ./run.sheksekusi. Saya telah mencoba returnjuga, yang tidak berfungsi dengan baik dalam ./run.sheksekusi.

Secara umum, saya tertarik mengapa ini terjadi, dan apa perbedaan antara menggunakan "sumber" dan "." untuk eksekusi skrip?

Richard
sumber

Jawaban:

16

Sebelum menjawab, saya pikir beberapa klarifikasi diperlukan. Mari kita menganalisis tiga baris berikut:

source run.sh
. run.sh
./run.sh

Dua baris pertama persis sama: .sebenarnya alias untuk source. Apa yang sourcedilakukan adalah mengeksekusi skrip shell dalam konteks saat ini, maka panggilan untuk exitkeluar dari shell.

Namun, baris ketiga (yang membingungkan Anda) tidak ada hubungannya dengan baris lainnya. ./run.shhanya jalan, dan sama dengan (misalnya) /home/user/run.shatau /usr/bin/something. Selalu ingat bahwa perintah dalam shell dipisahkan oleh spasi. Jadi, dalam hal ini, perintahnya bukan ., tetapi adalah ./run.sh: ini berarti bahwa sub-shell akan dieksekusi dan bahwa exitakan memiliki efek hanya pada sub-shell.

Andrea Corbellini
sumber
5

Tiga jalan:

Anda dapat melampirkan script dalam suatu fungsi dan hanya menggunakan kembali.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

Anda dapat menguji apakah skrip tersebut bersumber dari shell interaktif.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Anda dapat mencoba untuk kembali, dan jika gagal, keluar.

return 1 2>/dev/null || exit 1
geirha
sumber
Adakah petunjuk bagaimana mantra sihir $- = *i* bekerja?
deadbeef404
@ deadbeef404 Parameter khusus -memegang bendera opsi yang sedang aktif. Tes memeriksa apakah -ibendera aktif. Lihat gnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha
1

Pikirkan perintah 'sumber' seperti dalam pernyataan 'sertakan'. Dibutuhkan konten argumen dan menjalankannya seolah-olah itu dijalankan secara langsung. Dalam hal ini perintah Anda adalah 'sumber' dengan argumen 'run.sh' dan run.sh dijalankan persis seolah-olah Anda telah mengetik konten run.sh ke dalam baris perintah Anda.

Ketika Anda menjalankan './run.sh', './run.sh' adalah perintah Anda dan tidak memiliki argumen. Karena file ini teks biasa dan bukan biner, shell Anda mencari juru bahasa di shebang ('#!' Di baris pertama) dan menemukan '/ bin / bash'. Jadi shell Anda kemudian memulai instance baru bash dan konten run.sh dijalankan di dalam instance baru ini.

Pada contoh pertama, ketika bash mencapai perintah 'keluar' itu dijalankan persis seolah-olah Anda telah mengetiknya di baris perintah. Dalam contoh kedua ini dijalankan dalam proses bash, shell Anda mulai, jadi hanya instance bash ini yang menerima perintah 'keluar'.

Saat Anda mengetikkan baris ke bash, apa pun sebelum spasi pertama diperlakukan sebagai perintah dan apa pun yang berikut diperlakukan sebagai argumen. Perintah '.' adalah alias dari 'sumber'. Ketika Anda menjalankan '. run.sh 'the'. ' adalah perintah pada itu sendiri karena dipisahkan dari argumennya oleh spasi. Ketika Anda menjalankan './run.sh' perintah Anda adalah './run.sh' dan '.' adalah bagian dari jalur relatif untuk menjalankan.sh dengan '.' mewakili folder Anda saat ini.

merokok2345
sumber
Jika Anda seorang programmer C / C ++ yang ingin menjadi lebih baik dengan shell / bash scripting, ini adalah jawaban yang tepat.
Justin