вибираючи між $ 0 і BASH_SOURCE


118

Як вибирати між "$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]}

BASH_SOURCEдодавали при bash-3.0-альфа. Можливо, у вас його немає, залежно від режиму тестування. Я виявив, що він відсутній як на ранньому Solaris, так і на OS X. Також дивіться повернення: може лише "повернутися" з функції або скрипту на U & L.SE.
jww

Відповіді:


174

Примітка. Для рішення, сумісного з POSIX, дивіться цю відповідь .

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

Крім того, як зазначає Чарльз Даффі , абонент $0може встановлювати довільне значення.
З іншого боку, $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]}vs$BASH_SOURCE .:

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

Використання цієї функції затьмарює той факт $arr це масив, саме тому популярний вкладиш оболонки shellcheck.net видає таке попередження (станом на це написання):

SC2128: Розширення масиву без індексу дає лише перший елемент.

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

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


тому $ BASH_SOURCE є більш загальним і працює за інших обставин?
Олександр Міллс

2
@AlexanderMills Так, якщо ви використовуєте Bash, $BASH_SOURCEце кращий вибір.
mklement0

18

Ці сценарії можуть допомогти проілюструвати. Зовнішній скрипт викликає середній скрипт, який викликає внутрішній сценарій:

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

1

Для переносимості використовуйте, ${BASH_SOURCE[0]}коли це визначено, та $0інше. Це дає

${BASH_SOURCE[0]:-$0}

Зокрема, у скажімо zsh, $ 0 містить правильний файловий шлях, навіть якщо сценарій sourced.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.