eligiendo entre $ 0 y BASH_SOURCE

118

¿Cómo se elige entre "$0"y"${BASH_SOURCE[0]}"

Esta descripción de GNU no me ayudó mucho.

    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
fuente
BASH_SOURCEse agregó en bash-3.0-alpha. Es posible que no lo tenga, dependiendo de su régimen de pruebas. Encontré que faltaba tanto en los primeros Solaris como en OS X. Consulte también return: solo puede "regresar" desde una función o un script de origen en U & L.SE.
jww

Respuestas:

174

Nota: Para obtener una solución compatible con POSIX, consulte esta respuesta .

${BASH_SOURCE[0]}(o, más simplemente, $BASH_SOURCE[1] ) contiene la ruta (potencialmente relativa) del script contenedor en todos los escenarios de invocación, en particular también cuando se obtiene el script , lo cual no es cierto para $0.

Además, como señala Charles Duffy , la persona que llama $0puede establecer un valor arbitrario .
Por otro lado, $BASH_SOURCE puede estar vacío, si no hay un archivo con nombre involucrado; p.ej:
echo 'echo "[$BASH_SOURCE]"' | bash

El siguiente ejemplo lo ilustra:

Guión foo:

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

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

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

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

$0es parte de la especificación del shell POSIX, mientras que BASH_SOURCE, como sugiere el nombre, es específico de Bash.


[1] Lectura opcional: ${BASH_SOURCE[0]}vs$BASH_SOURCE .:

Bash le permite hacer referencia al elemento 0de una variable de matriz usando notación escalar : en lugar de escribir ${arr[0]}, puede escribir $arr; en otras palabras: si hace referencia a la variable como si fuera un escalar , obtiene el elemento en index 0.

El uso de esta característica oculta el hecho de que $arres una matriz, por lo que el popular linter shellcheck.net emite la siguiente advertencia (al momento de escribir este artículo):

SC2128: Expandir una matriz sin un índice solo da el primer elemento.

En una nota al margen: si bien esta advertencia es útil, podría ser más precisa, porque no necesariamente obtendrá el primer elemento: es específicamente el elemento en el índice 0que se devuelve, por lo que si el primer elemento tiene un índice más alto, que es posible en Bash - obtendrá la cadena vacía; tratar 'a[1]='hi'; echo "$a"'.
(Por el contrario, zshsiempre el renegado, de hecho , devuelve el primer elemento, independientemente de su índice).

Usted puede optar por evitar esta característica debido a su oscuridad, pero funciona predecible y, pragmáticamente hablando, usted rara vez, o nunca, necesidad de acceso ÍNDICES otra que 0de variable de matriz ${BASH_SOURCE[@]}.

mklement0
fuente
¿$ BASH_SOURCE es más genérico y funciona en más circunstancias?
Alexander Mills
2
@AlexanderMills Sí, si está usando Bash, $BASH_SOURCEes la mejor opción.
mklement0
18

Estos guiones pueden ayudar a ilustrar. El script externo llama al script intermedio, que llama al 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] = ''

Sin embargo, si cambiamos las llamadas del script a las sourcedeclaraciones:

$ 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
fuente
1

Para la portabilidad, utilícelo ${BASH_SOURCE[0]}cuando esté definido y de $0otro modo. Eso da

${BASH_SOURCE[0]:-$0}

En particular, por ejemplo, zsh, $ 0 contiene la ruta de archivo correcta incluso si el script es sourced.

user7610
fuente