Encuentra la ruta absoluta de un script


10

En un script, me meto en $0la posible ruta relativa a él. Para convertirlo a absoluto, he encontrado esta solución que no entiendo:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

Mi problema es la magia dentro de ${0%/*}y ${0##*/}. Parece que el primero extrae el nombre del directorio y el segundo extrae el nombre del archivo, simplemente no entiendo cómo.


2
Eso usa la expansión de parámetros, pero no funcionó para mí. Si su script solo se usará en Linux, puede usarlo readlink -f $0para obtener la ruta canónica.
Shawn J. Goff

1
@Shawn: 1 gran comentario de voto porque introdujo el pensamiento correcto: "Eso usa la expansión de parámetros, pero no funcionó para mí". La dirnameutilidad es útil aquí.
D4RIO

mywiki.wooledge.org/BashFAQ/028 y cyberciti.biz/faq/... dice BASH_SOURCEque es mejor que $0, como se $0le da al usuario de tecleado en el mando, que podría no ser la secuencia de comandos se está ejecutando actualmente.
Joel Purra

Respuestas:


8

Definiciones:

${string%substring} elimina la coincidencia más corta $substringdel final de $string.

${string##substring}elimina la coincidencia más larga $substringdesde el comienzo de $string.

Su ejemplo:

abspath=$(cd ${0%/*} && echo $PWD/${0##*/})

${0%/*} elimina todo después de la última barra oblicua y le da el nombre del directorio del script (que podría ser una ruta relativa).

${0##*/} elimina todo hasta la última barra oblicua, dándole solo el nombre de la secuencia de comandos.

Entonces, este comando cambia al directorio del script y concatena el directorio de trabajo actual (dado por $PWD) y el nombre del script que le proporciona la ruta absoluta.

Para ver lo que está pasando prueba:

echo ${0%/*}
echo ${0##*/}

Agregue comillas dobles alrededor de todas las expansiones variables para hacer frente a (casi todos) los nombres de archivo que contienen caracteres especiales de shell.
Gilles 'SO- deja de ser malvado'

10

Shawn tenía la solución más simple: readlink -f $0. Si desea estar absolutamente seguro de manejar nombres de archivos extraños, puede usar esto:

absolute_path_x="$(readlink -fn -- "$0"; echo x)"
absolute_path="${absolute_path_x%x}"

Documentación


1
Es bueno ver que las nuevas líneas finales se manejan correctamente. Lamentablemente readlink -fnes específico de Linux, NetBSD y OpenBSD.
Gilles 'SO- deja de ser malvado'

4

Aquí hay una forma más segura y legible de hacer este trabajo:

abspath=$(unset CDPATH && cd "$(dirname "$0")" && echo $PWD/$(basename "$0"))

Notas:

  • Si $0es un nombre de archivo simple sin ruta anterior, el script original fallará pero el que se proporciona aquí funcionará. (No es un problema $0pero podría estar en otras aplicaciones).
  • Cualquiera de los enfoques fallará si la ruta al archivo no existe realmente. (No es un problema $0, pero podría estar en otras aplicaciones).
  • Esto unsetes esencial si su usuario puede haber CDPATHconfigurado.
  • A diferencia readlink -fo realpath, esto va a funcionar en las versiones no-Linux de Unix (por ejemplo, Mac OS X).

2

Si desea aprender la expansión de parámetros de Shell, puede leerlo desde aquí , pero la expansión no siempre es una buena opción. En este caso, casi todos los sistemas tipo Unix tienen 2 buenas utilidades:

basename
dirname

El primero extraerá el nombre del archivo, mientras que el segundo extraerá la ruta, por lo tanto, si tiene $ 0, diga:

dirname $0

Y obtendrás el camino.

Salud


dirname puede devolver rutas relativas
opticyclic

0

Presentamos pwd, el bash incorporado. También se encuentra en el paquete GNU coreutils.

$ sh ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
$0: ./cygdrive/c/cygwin/home/../../../../home/jaroslav/tmp/somewhere.sh
cheeky binary from /home/jaroslav/tmp (/home/jaroslav/tmp)

$ cat /home/jaroslav/tmp/somewhere.sh

abs=$( cd `dirname "$0"` ; pwd -P)
absBin=$( cd `dirname "$0"` ; /bin/pwd -P)
echo \$0: $0
echo cheeky binary from $abs \($absBin\)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.