memilih antara $ 0 dan BASH_SOURCE

118

Bagaimana seseorang memilih antara "$0"dan"${BASH_SOURCE[0]}"

Penjelasan dari GNU ini tidak banyak membantu saya.

    BASH_SOURCE

 An array variable whose members are the source filenames where the
 corresponding shell function names in the FUNCNAME array variable are
 defined. The shell function ${FUNCNAME[$i]} is defined in the file
 ${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}
H2ONaCl
sumber
BASH_SOURCEtelah ditambahkan di bash-3.0-alpha. Anda mungkin tidak memilikinya, tergantung pada rezim pengujian Anda. Saya menemukan itu hilang pada awal Solaris dan OS X. Juga lihat kembali: hanya dapat 'kembali' dari fungsi atau skrip bersumber pada U & L.SE.
jww

Jawaban:

174

Catatan: Untuk solusi yang sesuai dengan POSIX, lihat jawaban ini .

${BASH_SOURCE[0]}(atau, lebih sederhananya, $BASH_SOURCE[1] ) berisi jalur (berpotensi relatif) dari skrip yang memuat dalam semua skenario pemanggilan, terutama juga ketika skrip bersumber , yang tidak benar untuk $0.

Lebih lanjut, seperti yang ditunjukkan Charles Duffy , $0dapat disetel ke nilai arbitrer oleh penelepon.
Di sisi lain, $BASH_SOURCE bisa kosong, jika tidak ada file bernama yang terlibat; misalnya:
echo 'echo "[$BASH_SOURCE]"' | bash

Contoh berikut menggambarkan hal ini:

Script foo:

#!/bin/bash
echo "[$0] vs. [${BASH_SOURCE[0]}]"

$ bash ./foo
[./foo] vs. [./foo]

$ ./foo
[./foo] vs. [./foo]

$ . ./foo
[bash] vs. [./foo]

$0adalah bagian dari spesifikasi shell POSIX, sedangkan BASH_SOURCE, seperti namanya, adalah khusus Bash.


[1] Opsional membaca: ${BASH_SOURCE[0]}vs$BASH_SOURCE :

Bash memungkinkan Anda untuk elemen referensi 0dari berbagai variabel menggunakan skalar notasi: alih-alih menulis ${arr[0]}, Anda dapat menulis $arr; dengan kata lain: jika Anda mereferensikan variabel seolah-olah itu adalah skalar , Anda mendapatkan elemen di index 0.

Menggunakan fitur ini mengaburkan fakta bahwa itu $arradalah sebuah array, itulah sebabnya shell-code linter shellcheck.net yang populer mengeluarkan peringatan berikut (saat tulisan ini dibuat):

SC2128: Memperluas larik tanpa indeks hanya memberikan elemen pertama.

Di samping catatan: Meskipun peringatan ini membantu, ini bisa lebih tepat, karena Anda belum tentu mendapatkan elemen pertama : Ini secara khusus adalah elemen pada indeks 0yang dikembalikan, jadi jika elemen pertama memiliki indeks yang lebih tinggi - yang mana dimungkinkan di Bash - Anda akan mendapatkan string kosong; coba 'a[1]='hi'; echo "$a"'.
(Sebaliknya, zsh, pernah murtad itu, memang tidak kembali elemen pertama, terlepas dari indeks).

Anda dapat memilih untuk menjauhkan diri dari fitur ini karena ketidakjelasan, tetapi bekerja diduga dan, pragmatis berbicara, Anda akan jarang, jika pernah, kebutuhan untuk mengakses indeks lain selain 0dari variabel array ${BASH_SOURCE[@]}.

mklement0
sumber
jadi $ BASH_SOURCE lebih umum dan berfungsi di lebih banyak situasi?
Alexander Mills
2
@AlexanderMills Ya, jika Anda menggunakan Bash, $BASH_SOURCEadalah pilihan yang lebih baik.
mklement0
18

Skrip ini dapat membantu mengilustrasikan. Skrip luar memanggil skrip tengah, yang memanggil skrip dalam:

$ cat outer.sh
#!/usr/bin/env bash
./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './inner.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = ''
$BASH_SOURCE[2] = ''

Namun, jika kita mengubah panggilan skrip menjadi sourcepernyataan:

$ cat outer.sh
#!/usr/bin/env bash
source ./middle.sh
$ cat middle.sh
#!/usr/bin/env bash
source ./inner.sh
$ cat inner.sh
#!/usr/bin/env bash
echo "\$0 = '$0'"
echo "\${BASH_SOURCE[0]} = '${BASH_SOURCE[0]}'"
echo "\${BASH_SOURCE[1]} = '${BASH_SOURCE[1]}'"
echo "\${BASH_SOURCE[2]} = '${BASH_SOURCE[2]}'"
$ ./outer.sh
$0 = './outer.sh'
$BASH_SOURCE[0] = './inner.sh'
$BASH_SOURCE[1] = './middle.sh'
$BASH_SOURCE[2] = './outer.sh'
Huw Walters
sumber
1

Untuk portabilitas, gunakan ${BASH_SOURCE[0]}jika sudah ditentukan, dan $0sebaliknya. Itu memberi

${BASH_SOURCE[0]:-$0}

Khususnya, katakanlah zsh, $ 0 memang berisi jalur file yang benar meskipun skripnya adalah sourced.

pengguna7610
sumber