wybór między $ 0 a BASH_SOURCE


119

Jak wybierać między "$0"i"${BASH_SOURCE[0]}"

Ten opis z GNU niewiele mi pomógł.

    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]}

BASH_SOURCEzostał dodany w bash-3.0-alpha. Możesz go nie mieć, w zależności od systemu testowania. Okazało się, że brakuje go zarówno we wczesnym Solarisie, jak i na OS X. Zobacz także return: can return: can only 'return' from a function or source script on U & L.SE.
jww

Odpowiedzi:


174

Uwaga: Aby uzyskać rozwiązanie zgodne z POSIX, zobacz tę odpowiedź .

${BASH_SOURCE[0]}(lub, prościej, $BASH_SOURCE[1] ) zawiera (potencjalnie względną) ścieżkę zawierającego skryptu we wszystkich scenariuszach wywołania, zwłaszcza gdy skrypt jest pozyskiwany , co nie jest prawdą $0.

Ponadto, jak wskazuje Charles Duffy , wywołujący $0może ustawić dowolną wartość.
Z drugiej strony, $BASH_SOURCE może być puste, jeśli nie ma nazwanego pliku; na przykład:
echo 'echo "[$BASH_SOURCE]"' | bash

Poniższy przykład ilustruje to:

Skrypt foo:

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

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

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

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

$0jest częścią specyfikacji powłoki POSIX, podczas gdy BASH_SOURCE, jak nazwa sugeruje, jest specyficzna dla Bash.


[1] Literatura: ${BASH_SOURCE[0]}vs$BASH_SOURCE :

Bash pozwala na elemencie bazowym 0wystąpienia tablicy zmiennej używając skalarnego notacji: zamiast pisać ${arr[0]}, można napisać $arr; innymi słowy: jeśli odniesiesz się do zmiennej tak, jakby była skalarem , otrzymasz element pod indeksem 0.

Korzystanie z tej funkcji przesłania fakt, że $arrjest to tablica, dlatego popularny linter z kodem powłoki shellcheck.net wyświetla następujące ostrzeżenie (w chwili pisania tego tekstu):

SC2128: Rozszerzenie tablicy bez indeksu daje tylko pierwszy element.

Na marginesie: chociaż to ostrzeżenie jest pomocne, może być bardziej precyzyjne, ponieważ niekoniecznie otrzymasz pierwszy element: 0zwracany jest konkretnie element w indeksie , więc jeśli pierwszy element ma wyższy indeks - który jest możliwe w Bash - otrzymasz pusty ciąg; spróbuj 'a[1]='hi'; echo "$a"'.
(Natomiast zsh, nigdy renegat, rzeczywiście robi powrotu pierwszy element, niezależnie od jej indeksu).

Możesz zrezygnować z tej funkcji ze względu na jej niejasność, ale działa ona przewidywalnie i, mówiąc pragmatycznie, rzadko, jeśli w ogóle, będziesz potrzebować dostępu do indeksów innych niż 0zmienna tablicowa ${BASH_SOURCE[@]}.


więc $ BASH_SOURCE jest bardziej ogólny i działa w większej liczbie przypadków?
Alexander Mills

2
@AlexanderMills Tak, jeśli używasz Bash, $BASH_SOURCEjest lepszym wyborem.
mklement0

18

Te skrypty mogą pomóc zilustrować. Skrypt zewnętrzny wywołuje skrypt środkowy, który wywołuje skrypt wewnętrzny:

$ 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] = ''

Jeśli jednak zmienimy wywołania skryptu na sourceinstrukcje:

$ 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'

1

W przypadku przenośności użyj, ${BASH_SOURCE[0]}gdy jest zdefiniowana, i $0poza tym. To daje

${BASH_SOURCE[0]:-$0}

Warto zauważyć, że na przykład zsh, $ 0 zawiera poprawną ścieżkę do pliku, nawet jeśli skrypt to sourced.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.