Wählen Sie zwischen $ 0 und BASH_SOURCE

117

Wie wählt man zwischen "$0"und"${BASH_SOURCE[0]}"

Diese Beschreibung von GNU hat mir nicht viel geholfen.

    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
quelle
BASH_SOURCEwurde bei bash-3.0-alpha hinzugefügt. Abhängig von Ihrem Testregime haben Sie es möglicherweise nicht. Ich habe festgestellt, dass es sowohl unter Solaris als auch unter OS X fehlt. Siehe auch return: Kann nur von einer Funktion oder einem Sourcing-Skript unter U & L.SE "zurückkehren" .
JWW

Antworten:

174

Hinweis: Eine POSIX-kompatible Lösung finden Sie in dieser Antwort .

${BASH_SOURCE[0]}(oder einfacher $BASH_SOURCE[1] ) enthält den (möglicherweise relativen) Pfad des enthaltenen Skripts in allen Aufrufszenarien, insbesondere auch, wenn das Skript bezogen wird , was nicht zutrifft $0.

Darüber hinaus kann Charles Duffy , wie Charles Duffy betont, vom Anrufer $0auf einen beliebigen Wert gesetzt werden.
Auf der anderen Seite $BASH_SOURCE kann leer sein, wenn keine benannte Datei beteiligt ist; z.B:
echo 'echo "[$BASH_SOURCE]"' | bash

Das folgende Beispiel veranschaulicht dies:

Skript foo:

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

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

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

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

$0ist Teil der POSIX-Shell-Spezifikation, während BASH_SOURCE, wie der Name schon sagt, Bash-spezifisch ist.


[1] Optional lesen: ${BASH_SOURCE[0]}gegen$BASH_SOURCE :

Mit Bash können Sie das Element 0einer Array- Variablen mithilfe der Skalarschreibweise referenzieren : Anstatt zu schreiben ${arr[0]}, können Sie schreiben $arr. Mit anderen Worten: Wenn Sie auf die Variable verweisen, als wäre sie ein Skalar , erhalten Sie das Element am Index 0.

Die Verwendung dieser Funktion verdeckt die Tatsache, dass $arres sich um ein Array handelt, weshalb der beliebte Shell-Code linter shellcheck.net die folgende Warnung ausgibt (zum Zeitpunkt dieses Schreibens):

SC2128: Wenn Sie ein Array ohne Index erweitern, erhalten Sie nur das erste Element.

Nebenbei bemerkt: Diese Warnung ist zwar hilfreich, könnte aber präziser sein, da Sie nicht unbedingt das erste Element erhalten: Es wird speziell das Element am Index 0zurückgegeben. Wenn also das erste Element einen höheren Index hat - welches ist in Bash möglich - Sie erhalten die leere Zeichenfolge; versuche es 'a[1]='hi'; echo "$a"'.
(Im Gegensatz dazu zsh, überhaupt der Renegat tatsächlich tut das erste Element zurück, unabhängig von dessen Index).

Sie können diese Funktion aufgrund ihrer Unklarheit meiden, sie funktioniert jedoch vorhersehbar, und pragmatisch gesehen müssen Sie selten, wenn überhaupt, auf andere Indizes als 0Array-Variablen zugreifen ${BASH_SOURCE[@]}.

mklement0
quelle
Also ist $ BASH_SOURCE allgemeiner und funktioniert unter mehr Umständen?
Alexander Mills
2
@AlexanderMills Ja, wenn Sie Bash verwenden, $BASH_SOURCEist dies die bessere Wahl.
mklement0
17

Diese Skripte können zur Veranschaulichung beitragen. Das äußere Skript ruft das mittlere Skript auf, das das innere Skript aufruft:

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

Wenn wir jedoch die Skriptaufrufe auf sourceAnweisungen ändern :

$ 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
quelle
0

Verwenden ${BASH_SOURCE[0]}Sie für die Portabilität, wenn es definiert ist, und $0anderweitig. Das gibt

${BASH_SOURCE[0]:-$0}

Insbesondere in zsh enthält $ 0 den richtigen Dateipfad, selbst wenn das Skript sourced ist.

user7610
quelle