martes, 29 de julio de 2014

¿Dónde se ubica este script?

Introducción


Al escribir un script a veces interesa saber en qué directorio está ubicado, por ejemplo, para acceder a algún recurso (un fichero de datos o de configuración asociado.)

Muchos scripts se alojan en un directorio propiedad del usuario y se ejecutan desde el propio directorio con la ruta "./". En tal caso, se podría acceder a un recurso con esa misma ruta. Sin embargo, nada impide ejecutarlo desde otro directorio, o incluso invocarlo desde otro script, con lo que esa forma de referenciar los recursos fallaría.

Aproximaciones


Algunas soluciones burdas, pero efectivas en muchos casos, son tan simples como:
  • Alojar el script y sus recursos en el mismo directorio.
  • Alojar los recursos en determinado directorio fijo y poner toda la ruta cada vez que se referencien desde el script (es mucho mejor poner una variable, claro).
Sin embargo, si deseamos reubicar el script o sus recursos, esas soluciones no sirven o implican al menos editar el script.

Solución


El comando readlink permite obtener el nombre canónico (con su ruta completa) de un fichero.
El comando which permite encontrar los ejecutables que coinciden con el argumento indicado. Por defecto, sólo muestra la ruta completa del primero que se encuentra recorriendo las rutas de la variable de entorno PATH.
En un script la variable $0 corresponde al nombre del propio script.
El comando dirname permite eliminar el sufijo no correspondiente al directorio de una ruta (normalmente el nombre de un fichero junto a su extensión). Es decir, extraer hasta el último directorio de una ruta.

Combinando todo lo anterior, es posible obtener el nombre real del fichero que se está ejecutando y a partir de él el directorio donde está ubicado:

MYSELF="$(which $(readlink -f ${0}))"
MY_PATH="$(dirname $(which $(readlink -f ${0})))"

La variable MYSELF contendrá el nombre canónico del script y la variable MY_PATH el directorio donde está alojado.

Ejemplo


Si quieres probar que funciona en varios casos, puedes hacer lo siguiente:

#!/bin/bash

MYSELF="$(which $(readlink -f ${0}))"
MY_PATH="$(dirname $(which $(readlink -f ${0})))"
echo "\$0=${0}"
echo "\$MYSELF=   ${MYSELF}"
echo "\$MY_PATH=  ${MY_PATH}"

  • Crear un script con las líneas que anteriores llamado "cat".
  • Poner el script en un directorio cualquiera de tu home.
  • Ir a /tmp/ y crear un enlace simbólico al script ejecutando
    $ ln -s /home/_your_user/.../cat
  • Alterar la variable PATH en la sesión actual:
    $ PATH=/tmp/:$PATH
  • Acceder a cualquier directorio y ejecutar
    $ cat something
En lugar de ejecutarse el comando cat del sistema, se ejecutará el script, mostrando su nombre canónico y el directorio donde está, aunque en realidad, se esté ejecutando el enlace simbólico que se puso en el directorio /tmp/.

Conclusión


Probablemente haya alguna solución mejor, más elegante o más precisa, pero hasta la fecha, a mi me ha bastado con esta.

Enlaces


Enlaces de interés relacionados con este artículo:

(Actualizado 29/07/2014)

2 comentarios:

  1. Muy elegante y útil la solución. Intentaré usarla a partir de ahora.

    ResponderEliminar
    Respuestas
    1. Si te resulta útil alguna vez, pues genial. Gracias por comentar.

      Eliminar