Подтвердить что ты не робот

Выбор между $0 и BASH_SOURCE

Как выбрать между "$0" и "${BASH_SOURCE[0]}"

Это описание из GNU не очень помогло мне.

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

Ответ 1

${BASH_SOURCE[0]} (или, проще говоря, $BASH_SOURCE [1]) содержит (потенциально относительный) путь содержащего сценария во всех сценариях вызова, особенно также при получении сценария, что неверно для $0.

Кроме того, как указывает Чарльз Даффи, вызывающий может установить произвольное значение $0.
С другой стороны, $BASH_SOURCE может быть пустым, если не $BASH_SOURCE именованный файл;например:
echo 'echo "[$BASH_SOURCE]"' | bash

Следующий пример иллюстрирует это:

Скрипт foo:

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

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

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

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

$0 является частью спецификации оболочки POSIX, тогда как BASH_SOURCE, как следует из названия, зависит от Bash.


[1] Необязательное чтение: ${BASH_SOURCE[0]} против $BASH_SOURCE:

Bash позволяет вам ссылаться на элемент 0 переменной массива, используя скалярную запись: вместо записи ${arr[0]} вы можете написать $arr; другими словами: если вы ссылаетесь на переменную, как на скаляр, вы получите элемент с индексом 0.

Использование этой функции скрывает тот факт, что $arr является массивом, поэтому популярный шелл-код linter shellcheck.net выдает следующее предупреждение (на момент написания статьи):

SC2128: Расширение массива без индекса дает только первый элемент.

Примечание: хотя это предупреждение полезно, оно может быть более точным, поскольку вы не обязательно получите первый элемент: именно элемент с индексом 0 возвращается, поэтому, если первый элемент имеет более высокий индекс - что возможно в Bash - вы получите пустую строку; попробуй 'a[1]='hi'; echo "$a"' 'a[1]='hi'; echo "$a"'.
(Напротив, zsh, когда-либо отступник, действительно возвращает первый элемент, независимо от его индекса).

Вы можете отказаться от этой функции из-за ее неясности, но она работает предсказуемо, и, прагматично говоря, вам редко, если вообще понадобится, получить доступ к индексам, отличным от 0 переменной массива ${BASH_SOURCE[@]}.

Ответ 2

Эти сценарии могут помочь проиллюстрировать. Внешний скрипт вызывает средний скрипт, который вызывает внутренний скрипт:

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

Однако, если мы изменим вызовы сценария на source операторы:

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