¿Cuál es una forma portátil para que un script (zsh) determine su ruta absoluta?
En Linux uso algo como
mypath=$(readlink -f $0)
... pero esto no es portátil. (Por ejemplo, readlinken Darwin no reconoce la -fbandera, ni tiene ningún equivalente.) (Además, usar readlinkpara esto es, ciertamente, un truco de aspecto bastante oscuro).
¿Qué es una forma más portátil?

Respuestas:
Con
zsh, es solo:Sin embargo, ahora para otros shells
realpath()yreadlink()son funciones estándar (esta última es una llamada al sistema),realpathyreadlinkno son comandos estándar, aunque algunos sistemas tienen uno u otro o ambos con diferentes comportamientos y características.Como a menudo, para la portabilidad, es posible que desee recurrir a
perl:Eso se comportaría más como GNU
readlink -fquerealpath()(GNUreadlink -e) en el sentido de que no se quejará si el archivo no existe mientras su nombre de directorio sí lo haga.fuente
.zshrc: vea esta publicación en su lugar.En zsh puedes hacer lo siguiente:
O, para obtener el directorio en el que reside el script:
Fuente: página del comando man zshexpn (1), sección EXPANSIÓN DE HISTORIA, Modificadores de subsección (o simplemente
info -f zsh -n Modifiers).fuente
readlink -fpreferiría ser$0:A.He estado usando esto durante varios años:
fuente
readlink -fes cuando el script en sí es un enlace simbólico.zsh, si ejecuto esto directamente o en el subshell (como se sugiere) mientras estoy en mi directorio de inicio (/home/ville), se imprime/home/ville/zsh.Esta sintaxis debe ser portátil a cualquier intérprete estilo shell Bourne (probado con
bash,ksh88,ksh93,zsh,mksh,dashybusybox sh):Esta versión agrega compatibilidad con el shell Bourne de AT&T heredado (no POSIX):
fuente
$PWDpuede ser exagerado, solo puede configurarlo como corriente absolutacd -P .. Dudo que funcione en bourneshell, pero debería funcionar en todos los que probó por primera vez. lo hace por mí de todos modos.zshydirnamerápidamente retiró su comentario ...Asumiendo que realmente se refería a la ruta absoluta, es decir, una ruta desde el directorio raíz:
Esto funciona en cualquier shell de estilo Bourne, por cierto.
Si se refería a una ruta con todos los enlaces simbólicos resueltos, ese es un asunto diferente.
readlink -ffunciona en Linux (excluyendo algunos sistemas BusyBox simplificados), FreeBSD, NetBSD, OpenBSD y Cygwin, pero no en OS / X, AIX, HP / UX o Solaris. Si es asíreadlink, puede llamarlo en un bucle:Si no lo tiene
readlink, puede aproximarlols -n, pero esto solo funciona silsno altera ningún carácter no imprimible en el nombre del archivo.(El extra
zes en caso de que el destino del enlace termine en una nueva línea, cuya sustitución de comando de otra manera se consumiría. Larealpathfunción no maneja ese caso para los nombres de directorio, por cierto).fuente
lsimplementación que manipule caracteres no imprimibles cuando la salida no vaya a una terminal?touch Stéphane; LC_ALL=C busybox ls Stéphane | cat→St??phane(eso si el nombre está en UTF-8, latin1 te da un sencillo?). Creo que también lo he visto en Unices comerciales más antiguos.busyboxes esto? según gitbusybox lsno ha habido un cambio de código desde 2011. Mibusybox ls- circa 2013 - no hace esto. Este uno - alrededor de 2012 - hace . Esto podría explicar por qué. ¿Ha creado subusyboxsoporte Unicode para incluir el soporte wchar? Es posible que desee probarlo, de lo contrario, verifique las opciones de compilación en elmkinitcpiobusyboxpaquete.Siempre que tenga permisos de ejecución en el directorio actual, o en el directorio desde el que ejecutó su script de shell, si desea una ruta absoluta a un directorio, todo lo que necesita es
cd.Paso 10 de
cdlas especificacionesY en
pwd -PEs porque
cd -Ptiene que establecer el directorio de trabajo actual a lo quepwd -Pdebería imprimirse y esocd -tiene que imprimir lo$OLDPWDque funciona:SALIDA
esperalo ...
SALIDA
Y cuando imprimo con
cd -estoy imprimiendo$OLDPWD.cdestablece$PWDtan pronto comocd -P .$PWDahora sea una ruta absoluta a/, por lo que no necesito ninguna otra variable. Y en realidad, ni siquiera debería necesitar el seguimiento,.pero hay un comportamiento específico de restablecer$PWDa$HOMEen un shell interactivo cuandocdes sin adornos. Por lo tanto, es un buen hábito desarrollar.Entonces, solo hacer lo anterior en la ruta
${0%/*}debería ser más que suficiente para verificar$0la ruta, pero en el caso de que$0sea un enlace suave, probablemente no pueda cambiar el directorio en él, desafortunadamente.Aquí hay una función que manejará eso:
Se esfuerza por hacer todo lo que podría en el shell actual, sin invocar un subshell, aunque hay subshells invocados por errores y enlaces blandos que no apuntan a directorios. Depende de un shell compatible con POSIX y de un compatible con POSIX
ls, así como de un dispositivo limpio_function()espacio de nombres . Todavía funcionará bien sin este último, aunque puede sobrescribirunsetalgunas funciones de shell actuales en ese caso. En general, todas estas dependencias deberían estar disponibles de manera bastante confiable en una máquina Unix.Llamado con o sin argumentos, lo primero que hace es restablecer
$PWDsu valor canónico: resuelve los enlaces a sus objetivos según sea necesario. Llamado sin argumentos y eso es todo; pero llamó con ellos y resolverá y canonizará la ruta para cada uno o imprimirá un mensaje parastderrqué no.Debido a que opera principalmente en el shell actual, debería poder manejar una lista de argumentos de cualquier longitud. También busca la
$_zdlmvariable (que tambiénunsetes cuando está terminada) e imprime su valor de C-escape inmediatamente a la derecha de cada uno de sus argumentos, cada uno de los cuales siempre va seguido de un solo\ncarácter de línea de hilo.Cambia mucho el directorio, pero, aparte de establecerlo en su valor canónico, no afecta
$PWD, aunque$OLDPWDno se puede contar de ninguna manera cuando está terminado.Intenta abandonar cada uno de sus argumentos lo antes posible. Primero intenta
cdentrar$1. Si puede, imprime la ruta canónica del argumento astdout. Si no puede, verifica si$1existe y no es un enlace suave. Si es cierto, se imprime.De esta manera, maneja cualquier argumento de tipo de archivo que el shell tenga permisos para abordar, a menos que
$1sea un enlace simbólico que no apunte a un directorio. En ese caso, llama alwhilebucle en una subshell.Llama
lspara leer el enlace. El directorio actual debe cambiarse a su valor inicial primero para poder manejar de manera confiable cualquier ruta de referencia y, por lo tanto, en la subshell de sustitución de comandos, la función hace:Se despoja de la izquierda de
lsla salida de tan poco como debe contener completamente el nombre del enlace y la cadena->. Si bien al principio intenté evitar hacer estoshifty$IFSresulta que este es el método más confiable tan cerca como puedo imaginar. Esto es lo mismo que hace poor_mans_readlink de Gilles, y está bien hecho.Repetirá este proceso en un bucle hasta que el nombre de archivo devuelto
lsdefinitivamente no sea un enlace suave. En ese punto, canonicaliza ese camino como antes con lascdimpresiones.Ejemplo de uso:
SALIDA
O posiblemente ...
SALIDA
fuente
¿Qué pasa con una línea simpática cuando hay Python disponible para evitar la redefinición de un algoritmo?
igual que https://stackoverflow.com/a/7305217
fuente