Apakah ada cara untuk skrip shell bersumber untuk menemukan jalan menuju dirinya sendiri? Saya terutama khawatir dengan bash, meskipun saya memiliki beberapa rekan kerja yang menggunakan tcsh.
Saya kira saya mungkin tidak memiliki banyak keberuntungan di sini, karena sumber menyebabkan perintah dieksekusi di shell saat ini, jadi $0
masih permintaan shell saat ini, bukan skrip yang bersumber. Pemikiran terbaik saya saat ini adalah melakukan source $script $script
, sehingga parameter posisi pertama berisi informasi yang diperlukan. Adakah yang punya cara yang lebih baik?
Untuk lebih jelasnya, saya sumber skrip, tidak menjalankannya:
source foo.bash
Jawaban:
Di
tcsh
,$_
di awal skrip akan berisi lokasi jika file tersebut bersumber dan$0
berisi jika dijalankan.Di Bash:
sumber
> tcsh --version\n tcsh 6.14.00 (Astron) 2005-03-25 (i486-intel-linux) options wide,nls,dl,al,kan,rh,nd,color,filec
. Sejauh sumber itu non-interaktif, file sumber dimasukkan ke dalam file induk seolah-olah itu benar-benar bagian dari itu (tidak bisa dibedakan) seperti yang Anda sebutkan dalam pertanyaan awal Anda. Saya pikir solusi parameter posisi Anda mungkin merupakan pendekatan terbaik. Namun, pertanyaan yang biasa adalah "mengapa Anda ingin melakukan itu" dan jawaban yang biasa untuk jawabannya adalah "jangan lakukan itu - lakukan ini sebagai gantinya" di mana "ini" sering disimpan ....
dansource
bekerja secara identik dalam hal ini. Catatan yang$_
harus diakses dalam pernyataan pertama dalam file, jika tidak maka akan berisi argumen terakhir dari perintah sebelumnya. Saya suka memasukkan shebang untuk referensi saya sendiri jadi saya tahu shell apa yang seharusnya dan untuk editor sehingga menggunakan highlight sintaks.source
, lalu melakukan.
. Saya minta maaf karena tidak kompeten. Mereka memang identik. Bagaimanapun,$BASH_SOURCE
bekerja.Saya pikir Anda bisa menggunakan
$BASH_SOURCE
variabel. Ini mengembalikan jalur yang dieksekusi:Jadi pada langkah selanjutnya kita harus memeriksa apakah path relatif atau tidak. Jika tidak relatif semuanya baik-baik saja. Jika itu kita bisa memeriksa path dengan
pwd
, menyatukan dengan/
dan$BASH_SOURCE
.sumber
source
mencari$PATH
jika nama yang diberikan tidak mengandung a/
. Urutan pencarian tergantung pada opsi shell, lihat manual untuk detailnya.mydir="$(cd "$(dirname "$BASH_SOURCE")"; pwd)"
akan berhasil?Demi ketelitian dan demi pencarian, inilah yang dilakukan ... Ini adalah wiki komunitas, jadi jangan ragu untuk menambahkan persamaan shell lainnya (jelas, $ BASH_SOURCE akan berbeda).
test.sh:
test2.sh:
Pesta:
Berlari
Zsh
sumber
called=$_; echo $called; echo $_
? Tidakkah ini dicetak$_
dua kali?$_
parameter khusus: "Pada shell startup, setel ke pathname absolut yang digunakan untuk memanggil shell atau skrip shell yang dieksekusi sebagaimana diteruskan dalam lingkungan atau daftar argumen. Selanjutnya, perluas ke yang terakhir argumen ke perintah sebelumnya, setelah ekspansi. Juga setel ke nama path lengkap yang digunakan untuk memanggil setiap perintah yang dieksekusi dan ditempatkan di lingkungan yang diekspor ke perintah itu. Saat memeriksa email, parameter ini menyimpan nama file email. "#! /bin/sh
yang membuatnya tidak berguna untuk sumber. Itu akan memulai instance baru/bin/sh
, mengatur variabel, lalu keluar dari instance itu, membiarkan instance panggilan tidak berubah.#
skrip shell adalah komentar.#!
(Shebang) hanya memiliki arti khusus sebagai baris pertama dari skrip yang dieksekusi. Sebagai baris pertama dari file yang bersumber, itu hanya komentar.Solusi ini hanya berlaku untuk bash dan bukan tcsh. Perhatikan bahwa jawaban yang umum diberikan
${BASH_SOURCE[0]}
tidak akan berfungsi jika Anda mencoba menemukan jalur dari dalam suatu fungsi.Saya menemukan baris ini selalu berfungsi, terlepas dari apakah file tersebut bersumber atau dijalankan sebagai skrip.
Jika Anda ingin mengikuti symlink, gunakan
readlink
jalur yang Anda dapatkan di atas, secara rekursif atau non-rekursif.Berikut ini skrip untuk mencobanya dan membandingkannya dengan solusi yang diusulkan lainnya. Gunakan sebagai
source test1/test2/test_script.sh
ataubash test1/test2/test_script.sh
.Alasan one-liner berfungsi dijelaskan oleh penggunaan
BASH_SOURCE
variabel lingkungan dan asosiasinyaFUNCNAME
.[Sumber: Bash manual]
sumber
Ini bekerja untuk saya di bash, dash, ksh, dan zsh:
Output untuk cangkang ini:
Saya mencoba membuatnya bekerja untuk csh / tcsh, tetapi terlalu sulit; Saya berpegang teguh pada POSIX.
sumber
Saya agak bingung dengan jawaban komunitas wiki (dari Shawn J. Goff), jadi saya menulis naskah untuk menyelesaikan masalah. Tentang
$_
, saya menemukan ini: Penggunaan_
sebagai variabel lingkungan dilewatkan ke perintah . Ini adalah variabel lingkungan sehingga mudah untuk menguji nilainya secara salah.Di bawah ini adalah skrip, lalu hasilnya. Mereka juga ada di inti ini .
test-shell-default-variables.sh
Output dari
./test-shell-default-variables.sh {da,ba,z,k}sh
Apa yang kami pelajari?
$BASH_SOURCE
$BASH_SOURCE
bekerja di bash dan hanya di bash.$0
adalah ketika file saat ini bersumber dari file lain. Dalam hal ini,$BASH_PROFILE
berisi nama file sumber, bukan dari file sumber.$0
$0
memiliki nilai yang sama dengan$BASH_SOURCE
di bash.$_
$_
dibiarkan tak tersentuh oleh tanda hubung dan ksh.$_
meluruh ke argumen terakhir dari panggilan terakhir.$_
ke "bash".$_
tidak tersentuh. (Saat sumber, itu hanya hasil dari aturan "argumen terakhir").Symlinks
ksh
SH
sh
, mengenai tes-tes itu, itu berperilaku seperti tanda hubung.sumber
Untuk bash shell, saya menemukan jawaban @Dennis Williamson sangat membantu, tetapi tidak berhasil dalam kasus
sudo
. Ini tidak:sumber
Untuk membuat skrip Anda kompatibel dengan bash dan zsh alih-alih menggunakan pernyataan if, Anda cukup menulis
${BASH_SOURCE[0]:-${(%):-%x}}
. Nilai yang dihasilkan akan diambil dariBASH_SOURCE[0]
saat itu ditentukan, dan${(%):-%x}}
ketika BASH_SOURCE [0] tidak ditentukan.sumber
tl; dr
script=$(readlink -e -- "${BASH_SOURCE}")
(untuk bash jelas)$BASH_SOURCE
uji kasusfile yang diberikan
/tmp/source1.sh
source
file dengan cara yang berbedasource
dari/tmp
source
dari/
source
dari jalur relatif berbeda/tmp/a
dan/var
mengenai
$0
dalam semua kasus, jika skrip memiliki perintah yang ditambahkan
maka
source
skrip selalu dicetaknamun , jika skrip dijalankan , mis
maka
$0
akan menjadi nilai string/tmp/source1.sh
.sumber
jawaban ini menjelaskan bagaimana
lsof
dan sedikit grep magic adalah satu-satunya hal yang tampaknya memiliki peluang bekerja untuk file bersarang bersarang di bawah tcsh:sumber
Mungkin ini tidak akan berfungsi dengan symlink atau file sumber tetapi bekerja untuk file normal. Diambil sebagai referensi mondar-mandir. @kenorb Tanpa dirname, tautan baca, BASH_SOURCE.
sumber
$0
memberi Anda informasi tentang skrip yang sedang berjalan , bukan yang bersumber.Sebenarnya, "dirname $ 0" akan memberi Anda jalan menuju skrip, tetapi Anda harus menafsirkannya sedikit:
Anda harus bersiap untuk menangani "." sebagai nama direktori dalam beberapa keadaan umum. Saya akan bereksperimen sedikit, karena saya ingat dirname built-in untuk ksh melakukan sesuatu yang sedikit berbeda ketika "." muncul di PATH.
sumber
$0
cukup berisi "bash" untuk shell interaktif, dan hanya itu yang dilihat skrip bersumber.