¿Hay alguna manera para que un script de shell de origen descubra el camino hacia sí mismo? Me preocupa principalmente bash, aunque tengo algunos compañeros de trabajo que usan tcsh.
Supongo que es posible que no tenga mucha suerte aquí, ya que el abastecimiento hace que los comandos se ejecuten en el shell actual, por $0
lo que sigue siendo la invocación del shell actual, no el script de origen. Mi mejor pensamiento actualmente es hacerlo source $script $script
, para que el primer parámetro posicional contenga la información necesaria. Alguien tiene una mejor manera?
Para ser claros, estoy buscando el script, no ejecutándolo:
source foo.bash
Respuestas:
En
tcsh
,$_
al comienzo de la secuencia de comandos contendrá la ubicación si el archivo se obtuvo y lo$0
contiene si se ejecutó.En Bash:
fuente
> tcsh --version\n tcsh 6.14.00 (Astron) 2005-03-25 (i486-intel-linux) options wide,nls,dl,al,kan,rh,nd,color,filec
. En cuanto a la obtención de fuentes de manera no interactiva, el archivo fuente se incluye en el archivo principal como si realmente fuera parte de él (indistintamente) como usted menciona en su pregunta original. Creo que su solución de parámetros posicionales es probablemente el mejor enfoque. Sin embargo, la pregunta habitual es "¿por qué quieres hacer eso?" Y la respuesta habitual a la respuesta es "no hagas eso, haz esto en su lugar", donde "esto" suele almacenarse ....
esource
trabajado de forma idéntica en este sentido. Tenga en cuenta que$_
debe accederse en la primera instrucción del archivo; de lo contrario, contendrá el último argumento del comando anterior. Me gusta incluir el shebang para mi propia referencia, así que sé para qué shell debe ser y para el editor, por lo que utiliza el resaltado de sintaxis.source
, luego haciendo.
. Pido disculpas por ser incompetente. De hecho son idénticos. De todos modos,$BASH_SOURCE
funciona.Creo que podrías usar
$BASH_SOURCE
variable. Devuelve la ruta que se ejecutó:Entonces, en el siguiente paso, debemos verificar si la ruta es relativa o no. Si no es relativo, todo está bien. Si es así, podríamos verificar la ruta con
pwd
, concatenar con/
y$BASH_SOURCE
.fuente
source
en cuenta que busca$PATH
si el nombre de pila no contiene un/
. El orden de búsqueda depende de las opciones de shell, consulte el manual para más detalles.mydir="$(cd "$(dirname "$BASH_SOURCE")"; pwd)"
funcionaría?Por rigor y por el bien de los buscadores, esto es lo que hacen ... Es un wiki de la comunidad, así que siéntase libre de agregar otros equivalentes de shell (obviamente, $ BASH_SOURCE será diferente).
test.sh:
test2.sh:
Golpetazo:
Guión, correr precipitadamente, precipitarse, ir de prisa
Zsh
fuente
called=$_; echo $called; echo $_
? ¿No se imprimirá esto$_
dos veces?$_
parámetro especial: "Al iniciar el shell, establezca el nombre de ruta absoluto utilizado para invocar el shell o el script de shell que se ejecuta como se pasa en el entorno o la lista de argumentos. Posteriormente, se expande hasta el último argumento para el comando anterior, después de la expansión. También se establece en el nombre de ruta completo utilizado para invocar cada comando ejecutado y colocado en el entorno exportado a ese comando. Al verificar el correo, este parámetro contiene el nombre del archivo de correo ".#! /bin/sh
que lo hace inútil para la fuente. Eso comenzaría una nueva instancia de/bin/sh
, establecer variables, luego salir de esa instancia, dejando la instancia de llamada sin cambios.#
en un script de shell es un comentario.#!
(shebang) tiene su significado especial solo como la primera línea de un script que se ejecuta. Como la primera línea de un archivo que se obtiene, es solo un comentario.Esta solución se aplica solo a bash y no a tcsh. Tenga en cuenta que la respuesta comúnmente proporcionada
${BASH_SOURCE[0]}
no funcionará si intenta encontrar la ruta desde una función.He encontrado que esta línea siempre funciona, independientemente de si el archivo se obtiene o se ejecuta como un script.
Si desea seguir el uso de enlaces simbólicos
readlink
en la ruta que obtiene arriba, recursivamente o no recursivamente.Aquí hay un script para probarlo y compararlo con otras soluciones propuestas. Invocarlo como
source test1/test2/test_script.sh
obash test1/test2/test_script.sh
.La razón por la que funciona One-liner se explica por el uso de la
BASH_SOURCE
variable de entorno y su asociadoFUNCNAME
.[Fuente: manual de Bash]
fuente
Esto funcionó para mí en bash, dash, ksh y zsh:
Salida para estos proyectiles:
Traté de hacerlo funcionar para csh / tcsh, pero es demasiado difícil; Me estoy quedando con POSIX.
fuente
Estaba un poco confundido por la respuesta wiki de la comunidad (de Shawn J. Goff), así que escribí un guión para resolver las cosas. Acerca de
$_
, encontré esto: Uso de_
como una variable de entorno pasada a un comando . Es una variable de entorno, por lo que es fácil probar su valor incorrectamente.A continuación se muestra el script, luego es salida. También están en esta esencia .
test-shell-default-variables.sh
Salida de
./test-shell-default-variables.sh {da,ba,z,k}sh
Que aprendimos
$BASH_SOURCE
$BASH_SOURCE
funciona en bash y solo en bash.$0
es cuando el archivo actual fue originado por otro archivo. En ese caso,$BASH_PROFILE
contiene el nombre del archivo de origen, en lugar del nombre del archivo de origen.$0
$0
tiene el mismo valor que$BASH_SOURCE
en bash.$_
$_
se deja sin tocar por guión y ksh.$_
decae al último argumento de la última llamada.$_
a "bash".$_
sin tocar. (cuando se busca, es solo el resultado de la regla del "último argumento").Enlaces simbólicos
ksh
sh
sh
, con respecto a esas pruebas, se comporta como un guión.fuente
Para el bash shell, encontré la respuesta de @Dennis Williamson más útil, pero no funcionó en el caso de
sudo
. Esto hace:fuente
Para hacer que su script sea compatible con bash y zsh en lugar de usar sentencias if, simplemente puede escribir
${BASH_SOURCE[0]:-${(%):-%x}}
. El valor resultante se tomará deBASH_SOURCE[0]
cuando está definido y${(%):-%x}}
cuando BASH_SOURCE [0] no está definido.fuente
tl; dr
script=$(readlink -e -- "${BASH_SOURCE}")
(para bash obviamente)$BASH_SOURCE
Casos de pruebaarchivo dado
/tmp/source1.sh
source
el archivo de diferentes manerassource
de/tmp
source
de/
source
de diferentes caminos relativos/tmp/a
y/var
respecto a
$0
en todos los casos, si el script tenía el comando agregado
entonces
source
el guión siempre se imprimesin embargo , si se ejecutó el script , por ej.
entonces
$0
sería un valor de cadena/tmp/source1.sh
.fuente
esta respuesta describe cómo
lsof
y un poco de magia grep es lo único que parece tener posibilidades de funcionar para archivos de origen anidados en tcsh:fuente
Tal vez esto no funcione con enlaces simbólicos o archivos de origen, pero funcionará para archivos normales. Tomado como referencia para. @kenorb Sin nombre de directorio, enlace de lectura, BASH_SOURCE.
fuente
$0
brinda información sobre el script que se está ejecutando actualmente , no uno de origen.En realidad, "dirname $ 0" te dará la ruta al script, pero debes interpretarlo un poco:
Tienes que prepararte para manejar "." como el nombre del directorio en algunas circunstancias comunes. Experimentaría un poco, ya que recuerdo el nombre de directorio incorporado en ksh haciendo las cosas de manera un poco diferente cuando "." aparece en RUTA.
fuente
$0
simplemente contiene "bash" para un shell interactivo, y eso es todo lo que ve el script de origen.