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.

maaartinus
fuente
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##*/}
dogbane
fuente
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

l0b0
fuente
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).
Matthias Fripp
fuente
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

D4RIO
fuente
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\)
Ярослав Рахматуллин
fuente