scegliendo tra $ 0 e BASH_SOURCE


118

Come si sceglie tra "$0"e"${BASH_SOURCE[0]}"

Questa descrizione da GNU non mi ha aiutato molto.

    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è stato aggiunto a bash-3.0-alpha. Potresti non averlo, a seconda del tuo regime di test. L'ho trovato mancante sia sui primi Solaris che su OS X. Vedi anche return: può solo "tornare" da una funzione o da uno script originato su U & L.SE.
jww

Risposte:


174

Nota: per una soluzione conforme a POSIX, vedere questa risposta .

${BASH_SOURCE[0]}(o, più semplicemente, $BASH_SOURCE[1] ) contiene il percorso (potenzialmente relativo) dello script contenitore in tutti gli scenari di invocazione, in particolare anche quando lo script è originato , il che non è vero per $0.

Inoltre, come sottolinea Charles Duffy , $0può essere impostato su un valore arbitrario dal chiamante.
D'altro canto, $BASH_SOURCE può essere vuoto, se non è coinvolto alcun file denominato; per esempio:
echo 'echo "[$BASH_SOURCE]"' | bash

Il seguente esempio lo illustra:

Script foo:

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

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

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

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

$0fa parte della specifica della shell POSIX, mentre BASH_SOURCE, come suggerisce il nome, è specifica di Bash.


[1] Lettura facoltativa: ${BASH_SOURCE[0]}vs$BASH_SOURCE .:

Bash ti permette di fare riferimento a un elemento 0di una variabile di array usando la notazione scalare : invece di scrivere ${arr[0]}, puoi scrivere $arr; in altre parole: se si fa riferimento alla variabile come se fosse uno scalare , si ottiene l'elemento all'indice 0.

L'uso di questa funzione nasconde il fatto che $arrè un array, motivo per cui il popolare codice shell linter shellcheck.net emette il seguente avviso (al momento della stesura di questo documento):

SC2128: l'espansione di un array senza un indice fornisce solo il primo elemento.

Nota a margine: sebbene questo avviso sia utile, potrebbe essere più preciso, perché non otterrai necessariamente il primo elemento: è specificamente l'elemento all'indice 0che viene restituito, quindi se il primo elemento ha un indice più alto, che è possibile in Bash - otterrai la stringa vuota; provare 'a[1]='hi'; echo "$a"'.
(Al contrario, zshmai il rinnegato, anzi fa ritornare il primo elemento, indipendentemente dal suo indice).

Puoi scegliere di evitare questa funzione a causa della sua oscurità, ma funziona in modo prevedibile e, pragmaticamente parlando, raramente, se non mai, avrai bisogno di accedere a indici diversi dalla 0variabile di array ${BASH_SOURCE[@]}.


quindi $ BASH_SOURCE è più generico e funziona in più circostanze?
Alexander Mills

2
@AlexanderMills Sì, se stai usando Bash, $BASH_SOURCEè la scelta migliore.
mklement0

18

Questi script possono aiutare a illustrare. Lo script esterno chiama lo script centrale, che chiama lo script interno:

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

Tuttavia, se cambiamo le chiamate di script in sourceistruzioni:

$ 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

Per la portabilità, utilizzare ${BASH_SOURCE[0]}quando è definito e $0altrimenti. Questo dà

${BASH_SOURCE[0]:-$0}

In particolare, diciamo zsh, $ 0 contiene il percorso file corretto anche se lo script è sourced.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.