¿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, readlink
en Darwin no reconoce la -f
bandera, ni tiene ningún equivalente.) (Además, usar readlink
para 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),realpath
yreadlink
no 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 -f
querealpath()
(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 -f
preferiría ser$0:A
.He estado usando esto durante varios años:
fuente
readlink -f
es 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
,dash
ybusybox sh
):Esta versión agrega compatibilidad con el shell Bourne de AT&T heredado (no POSIX):
fuente
$PWD
puede 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.zsh
ydirname
rá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 -f
funciona 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 sils
no altera ningún carácter no imprimible en el nombre del archivo.(El extra
z
es 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. Larealpath
función no maneja ese caso para los nombres de directorio, por cierto).fuente
ls
implementació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.busybox
es esto? según gitbusybox ls
no 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 subusybox
soporte Unicode para incluir el soporte wchar? Es posible que desee probarlo, de lo contrario, verifique las opciones de compilación en elmkinitcpio
busybox
paquete.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
cd
las especificacionesY en
pwd -P
Es porque
cd -P
tiene que establecer el directorio de trabajo actual a lo quepwd -P
debería imprimirse y esocd -
tiene que imprimir lo$OLDPWD
que funciona:SALIDA
esperalo ...
SALIDA
Y cuando imprimo con
cd -
estoy imprimiendo$OLDPWD
.cd
establece$PWD
tan pronto comocd -P .
$PWD
ahora 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$PWD
a$HOME
en un shell interactivo cuandocd
es 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$0
la ruta, pero en el caso de que$0
sea 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 sobrescribirunset
algunas 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
$PWD
su 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 parastderr
qué 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
$_zdlm
variable (que tambiénunset
es 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\n
carácter de línea de hilo.Cambia mucho el directorio, pero, aparte de establecerlo en su valor canónico, no afecta
$PWD
, aunque$OLDPWD
no se puede contar de ninguna manera cuando está terminado.Intenta abandonar cada uno de sus argumentos lo antes posible. Primero intenta
cd
entrar$1
. Si puede, imprime la ruta canónica del argumento astdout
. Si no puede, verifica si$1
existe 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
$1
sea un enlace simbólico que no apunte a un directorio. En ese caso, llama alwhile
bucle en una subshell.Llama
ls
para 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
ls
la salida de tan poco como debe contener completamente el nombre del enlace y la cadena->
. Si bien al principio intenté evitar hacer estoshift
y$IFS
resulta 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
ls
definitivamente no sea un enlace suave. En ese punto, canonicaliza ese camino como antes con lascd
impresiones.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