Encontrar la ubicación del script de shell de origen

8

¿Es posible que un script de shell de origen conozca su ubicación? He leído la determinación de ruta de acceso a shell script de origen , pero las respuestas se centran en bashy tcshy fallar si se utiliza un shell POSIX. $0tampoco es la solución y produce resultados incorrectos .

Una solución no necesita ser 100% confiable. Es poco probable que la ruta contenga enlaces duros o simbólicos.

# sourcing the script should yield the absolute path to the script
. somedir/thescript

# within “thescript”
-> /tmp/foo/bar/somedir

Algunos antecedentes: el script es parte de una aplicación existente que contiene docenas de archivos binarios en un bindirectorio en una ubicación conocida (varía según la arquitectura) en relación con el script de origen. Para usar la aplicación, el usuario obtiene el script que antepone el bindirectorio al PATH, de modo que los binarios de la aplicación pueden invocarse fácilmente en el shell actual (cualquiera que sea el shell).

Marco
fuente
Por favor, una vez que compruebe este enlace, puede ser lo que está buscando paste.ubuntu.com/6242655
Rahul Patil
@RahulPatil Eso solo funciona en bash y es altamente inportable.
Marco
1
Estoy bastante seguro de que la respuesta es no. Solo encontró métodos específicos de shell porque no hay un método portátil. ¿Para qué necesitas esto? ¿Puede decirles a los usuarios del script que hagan algo diferente de . /path/to/scriptcomo MARCO_DIR=/path/to; . $MARCO_DIR/scripto eval "$(/path/to/script)"? @RahulPatil BASH_SOURCEes obviamente específico de bash.
Gilles 'SO- deja de ser malvado'
@Gilles Como dije, no necesita ser muy robusto. Pero no he encontrado una forma que funcione remotamente en los casos más simples en un shell POSIX. (Por lo tanto, la solución por el momento es que el uso de esta aplicación requiere uno de los shells compatibles.) Siéntase libre de publicar "no ..." como respuesta si esa es la respuesta.
Marco
@Gilles Cambiar la forma en que se configura la aplicación no es una opción. Rompería las instalaciones. Es por eso que me hubiera gustado hacer que el script sea más robusto sin cambiar la forma en que se llama. Al final, solo establece la RUTA, por lo que si el script falla, la alternativa es encontrar los binarios y agregar su ruta al entorno.
Marco

Respuestas:

9

La ubicación del script de origen no está disponible a menos que esté utilizando un shell que ofrece extensiones a la especificación POSIX. Puede probar esto con el siguiente fragmento:

env -i PATH=/usr/bin:/bin sh -c '. ./included.sh' | grep included

donde included.shcontiene

echo "$0"
set

En bash, el nombre del script de origen está en $BASH_SOURCE. En zsh (en modo de compatibilidad zsh, no en modo de compatibilidad sh o ksh), está en $0(tenga en cuenta que en una función, $0es el nombre de la función en su lugar). En pdksh y dash, no está disponible. En ksh93, este método no revela la solución, pero la ruta completa al script incluido está disponible como ${.sh.file}.

Si requerir bash o ksh93 o zsh es lo suficientemente bueno, puede usar este fragmento:

if [ -n "$BASH_SOURCE" ]; then
  this_script=$BASH_SOURCE
elif [ -n "$ZSH_VERSION" ]; then
  setopt function_argzero
  this_script=$0
elif eval '[[ -n ${.sh.file} ]]' 2>/dev/null; then
  eval 'this_script=${.sh.file}'
else
  echo 1>&2 "Unsupported shell. Please use bash, ksh93 or zsh."
  exit 2
fi

Puede intentar adivinar la ubicación del script mirando qué archivos ha abierto el shell. Experimentalmente, esto parece funcionar con dash y pdksh, pero no con bash o ksh93, que al menos para un script corto han cerrado el archivo de script para cuando llegan a ejecutarlo.

  open_file=$(lsof -F n -p $$ | sed -n '$s/^n//p')
  if [ -n "$open_file" ]; then
    # best guess: $open_file is this script
  fi

Es posible que el script no sea el archivo con el descriptor con el número más alto si el script se origina dentro de un script complejo que se ha estado jugando con redireccionamientos. Es posible que desee recorrer los archivos abiertos. No se garantiza que esto funcione de todos modos. La única forma confiable de localizar un script de fuente es usar bash, ksh93 o zsh.


Si puede cambiar la interfaz, entonces, en lugar de obtener su script, haga que imprima un fragmento de shell para que se lo pase a evalla persona que llama. Esto es lo que suelen hacer los scripts para establecer variables de entorno. Permite que su script se escriba independientemente de los caprichos del shell y la configuración de shell del llamante.

#!/bin/sh
FOO_DIR=$(dirname -- "$0")
cat <<EOF
FOO_DIR='$(printf %s "$FOO_DIR" | sed "s/'/'\\''/g")'
PATH="\$PATH:$FOO_DIR/bin";
export FOO_DIR PATH
EOF

En la persona que llama: eval "`/path/to/setenv`"

Gilles 'SO- deja de ser malvado'
fuente
0

Agregando a la respuesta de Gilles, PUEDE ser capaz de obtener el script de shell ( if $0 = ash) a través de /proc/$$ interface. No sé cuán preciso es esto, pero /proc/$$/fd/11parece que siempre apunta a this_script con la ceniza de BusyBox.

Brindar esto como una posible respuesta a quienes se encuentran con esta página (como lo hice yo).

La última respuesta se eliminó, por lo tanto, mi reclamo de este funcionamiento se prueba en 4 plataformas HW diferentes (x86, ARM, XLP y powerpc). Todos dan la misma respuesta de fd / 11. Un enlace de lectura /proc/$$/fd/11produce mi script.

Andy

A. Kennedy
fuente