¿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 $0lo 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$0contiene 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 ....esourcetrabajado 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_SOURCEfunciona.Creo que podrías usar
$BASH_SOURCEvariable. 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
sourceen cuenta que busca$PATHsi 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/shque 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
readlinken 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.shobash test1/test2/test_script.sh.La razón por la que funciona One-liner se explica por el uso de la
BASH_SOURCEvariable 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}shQue aprendimos
$BASH_SOURCE$BASH_SOURCEfunciona en bash y solo en bash.$0es cuando el archivo actual fue originado por otro archivo. En ese caso,$BASH_PROFILEcontiene el nombre del archivo de origen, en lugar del nombre del archivo de origen.$0$0tiene el mismo valor que$BASH_SOURCEen 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_SOURCECasos de pruebaarchivo dado
/tmp/source1.shsourceel archivo de diferentes manerassourcede/tmpsourcede/sourcede diferentes caminos relativos/tmp/ay/varrespecto a
$0en todos los casos, si el script tenía el comando agregado
entonces
sourceel guión siempre se imprimesin embargo , si se ejecutó el script , por ej.
entonces
$0sería un valor de cadena/tmp/source1.sh.fuente
esta respuesta describe cómo
lsofy 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
$0brinda 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
$0simplemente contiene "bash" para un shell interactivo, y eso es todo lo que ve el script de origen.