¿Importa si existe /foo/baro incluso /fooexiste, o solo le interesa el aspecto de manipulación de cadenas de acuerdo con las reglas de nombre de ruta?
Chen Levy el
55
@twalberg ... eso es un poco artificial ...
Camilo Martin
2
No @CamiloMartin ideó en absoluto - que hace exactamente lo que hace la pregunta - transforma /foo/bar/..a /foo, y el uso de un bashcomando. Si hay otros requisitos que no están establecidos, entonces quizás deberían ser ...
twalberg
14
@twalberg Has estado haciendo demasiado TDD -_- '
Camilo Martin
Respuestas:
193
si desea cortar parte de un nombre de archivo de la ruta, "dirname" y "basename" son sus amigos, y "realpath" también es útil.
dirname /foo/bar/baz # /foo/bar
basename /foo/bar/baz# baz
dirname $( dirname /foo/bar/baz )# /foo
realpath ../foo# ../foo: No such file or directory
realpath /tmp/../tmp/../tmp# /tmp
realpath alternativas
Si realpathsu shell no lo admite, puede intentar
readlink -f /path/here/..
también
readlink -m /path/there/../../
Funciona igual que
realpath -s /path/here/../../
en que el camino no necesita existir para ser normalizado.
Para aquellos de ustedes que necesitan una solución OS X, consulte la respuesta de Adam Liss a continuación.
Trenton
stackoverflow.com/a/17744637/999943 ¡ Esta es una respuesta muy relacionada! Me encontré con estas dos publicaciones de control de calidad en un día, y quería vincularlas.
Ambos realpathy readlinkprovienen de las utilidades principales de GNU, por lo que lo más probable es que obtenga ambos o ninguno. Si no recuerdo mal, la versión de readlink en Mac es ligeramente diferente a la de GNU: - \
Antoine 'hashar' Musso
100
No sé si hay un comando bash directo para hacer esto, pero generalmente lo hago
Esto normalizará pero no resolverá los enlaces blandos. Esto puede ser un error o una característica. :-)
Adam Liss
44
También tiene un problema si se define $ CDPATH; porque el "cd foo" cambiará a cualquier directorio "foo" que sea un subdirectorio de $ CDPATH, no solo un "foo" que esté en el directorio actual. Creo que debe hacer algo como: CDPATH = "" cd "$ {dirToNormalize}" && pwd -P.
mjs
77
La respuesta de Tim es definitivamente la más simple y portátil. CDPATH es fácil de manejar: dir = "$ (CDPATH no establecido && cd" $ dir "&& pwd)"
David Blevins
2
¡Esto podría ser muy peligroso ( rm -rf $normalDir) si dirToNormalize no existe!
Frank Meulenaar
44
Sí, probablemente sea mejor usar un &&según el comentario de @ DavidBlevins.
Elias Dorneles
54
Tratar realpath. A continuación se muestra la fuente en su totalidad, por la presente donada al dominio público.
// realpath.c: display the absolute path to a file or directory.// Adam Liss, August, 2007// This program is provided "as-is" to the public domain, without express or// implied warranty, for any non-profit use, provided this notice is maintained.#include<stdio.h>#include<stdlib.h>#include<string.h>#include<libgen.h>#include<limits.h>staticchar*s_pMyName;void usage(void);int main(int argc,char*argv[]){char
sPath[PATH_MAX];
s_pMyName = strdup(basename(argv[0]));if(argc <2)
usage();
printf("%s\n", realpath(argv[1], sPath));return0;}void usage(void){
fprintf(stderr,"usage: %s PATH\n", s_pMyName);
exit(1);}
Realmente deberías atravesar la parte con "Bonus: es un comando bash, ¡y está disponible en todas partes!" parte sobre realpath. También es mi favorito, pero en lugar de compilar su herramienta desde la fuente. Todo es para peso pesado, y la mayoría de las veces solo quieres readlink -f... Por cierto, readlinktampoco es un bash incorporado, sino parte de coreutilsUbuntu.
Tomasz Gandor
44
Usted ha dicho que está donando esto al dominio público, pero el encabezado también dice "para cualquier uso sin fines de lucro", ¿realmente quiere donarlo al dominio público? Eso significaría que puede usarse con fines comerciales con fines de lucro, así como sin fines de lucro ...
yo_y
36
Una solución portátil y confiable es usar python, que está preinstalado prácticamente en todas partes (incluido Darwin). Tienes dos opciones:
abspath devuelve una ruta absoluta pero no resuelve enlaces simbólicos:
BSD no tiene el indicador -f, lo que significa que esto fallará incluso en el último MacOS Mojave y muchos otros sistemas. Olvídate de usar -f si quieres portabilidad, muchos sistemas operativos se ven afectados.
sorin
1
@sorin. La pregunta no es sobre Mac, sino sobre Linux.
mattalxndr
14
readlinkes el estándar bash para obtener la ruta absoluta. También tiene la ventaja de devolver cadenas vacías si las rutas o una ruta no existe (dadas las banderas para hacerlo).
Para obtener la ruta absoluta a un directorio que puede existir o no, pero los padres de quién existen, use:
abspath=$(readlink -f $path)
Para obtener la ruta absoluta a un directorio que debe existir junto con todos los padres:
abspath=$(readlink -e $path)
Para canonizar la ruta dada y seguir enlaces simbólicos si existen, pero ignorar los directorios que faltan y simplemente devolver la ruta de todos modos, es:
abspath=$(readlink -m $path)
El único inconveniente es que readlink seguirá a los enlaces. Si no desea seguir los enlaces, puede usar esta convención alternativa:
abspath=$(cd ${path%/*}&& echo $PWD/${path##*/})
Eso conducirá a la parte del directorio de $ path e imprimirá el directorio actual junto con la parte del archivo de $ path. Si no puede chdir, obtienes una cadena vacía y un error en stderr.
readlinkEs una buena opción si está disponible. La versión de OS X no admite las opciones -eo -f. En los primeros tres ejemplos, debe tener comillas dobles $pathpara manejar espacios o comodines en el nombre del archivo. +1 para la expansión de parámetros, pero esto tiene una vulnerabilidad de seguridad. Si pathestá vacío, esto lo hará cda su directorio de inicio. Necesitas comillas dobles. abspath=$(cd "${path%/*}" && echo "$PWD/${path##*/}")
toxalot
Esto fue solo un ejemplo. Si estás empeñado en la seguridad, entonces realmente no deberías usar bash ni ninguna otra variante de shell. Además, bash tiene sus propios problemas cuando se trata de compatibilidad multiplataforma, además de tener problemas con el cambio de funcionalidad entre las principales versiones. OSX es solo una de las muchas plataformas con problemas relacionados con las secuencias de comandos de shell, sin mencionar que se basa en BSD. Cuando tiene que ser verdaderamente multiplataforma, debe ser compatible con POSIX, por lo que la expansión de parámetros realmente desaparece. Eche un vistazo a Solaris o HP-UX en algún momento.
Craig
66
No significa ningún delito aquí, pero es importante señalar problemas oscuros como este. Solo quiero una respuesta rápida a este problema trivial y hubiera confiado en ese código con cualquier / toda entrada si no fuera por el comentario anterior. También es importante admitir OS-X en estas discusiones bash. Desafortunadamente, hay muchos comandos que no son compatibles con OS-X, y muchos foros dan eso por sentado cuando se habla de Bash, lo que significa que continuaremos recibiendo muchos problemas multiplataforma a menos que se aborde más temprano que tarde.
Rebs
13
Antigua pregunta, pero hay una forma mucho más simple si se trata de nombres de ruta completos a nivel de shell:
abspath = "$ (cd" $ ruta "&& pwd)"
Como el cd ocurre en una subshell, no afecta el script principal.
Dos variaciones, suponiendo que sus comandos integrados de shell acepten -L y -P, son:
Personalmente, rara vez necesito este enfoque posterior a menos que me fascinen los enlaces simbólicos por alguna razón.
FYI: variación en la obtención del directorio de inicio de un script que funciona incluso si el script cambia su directorio actual más adelante.
name0 = "$ (nombre base" $ 0 ")"; #base name of script
dir0 = "$ (cd" $ (dirname "$ 0") "&& pwd)"; #absolute dir inicio
El uso de CD asegura que siempre tenga el directorio absoluto, incluso si el script se ejecuta mediante comandos como ./script.sh que, sin el cd / pwd, a menudo da solo ... Inútil si el script hace un cd más adelante.
Como señaló Adam Liss, realpathno se incluye en todas las distribuciones. Lo cual es una pena, porque es la mejor solución. El código fuente proporcionado es excelente, y probablemente comenzaré a usarlo ahora. Esto es lo que he estado usando hasta ahora, que comparto aquí solo para completar:
get_abs_path(){local PARENT_DIR=$(dirname "$1")
cd "$PARENT_DIR"local ABS_PATH="$(pwd)"/"$(basename "$1")"
cd ->/dev/null
echo "$ABS_PATH"}
Si usted quiere que los enlaces simbólicos a resolver, simplemente reemplazar pwdcon pwd -P.
Uno tiene la pwd -Popción para este caso ... Considere lo que sucedería si $(basename "$1")fuera un enlace simbólico a un archivo en otro directorio. El pwd -Púnico resuelve enlaces simbólicos en la parte del directorio de la ruta, pero no la parte del nombre base.
Sospecho que esto falla si el argumento no es un directorio. Supongamos que quiero saber a dónde / usr / bin / java conduce?
Edward Falk
1
Si sabe que es un archivo, puede pushd $(dirname /usr/bin/java)intentarlo.
schmunk
5
No es exactamente una respuesta, sino quizás una pregunta de seguimiento (la pregunta original no era explícita):
readlinkestá bien si realmente quieres seguir enlaces simbólicos. Pero también hay un caso de uso por el solo hecho de la normalización ./y ../y //secuencias, que se pueden hacer puramente sintáctico, sin canonizan enlaces simbólicos. readlinkno es bueno para esto, y tampoco lo es realpath.
for f in $paths;do(cd $f; pwd);done
funciona para caminos existentes, pero se rompe para otros.
Una sedsecuencia de comandos parecería ser una buena apuesta, excepto que no puede reemplazar iterativamente secuencias ( /foo/bar/baz/../..-> /foo/bar/..-> /foo) sin usar algo como Perl, que no es seguro asumir en todos los sistemas, o usar algún bucle feo para comparar la salida de seda su entrada
FWIW, una línea usando Java (JDK 6+):
jrunscript -e 'for (var i = 0; i < arguments.length; i++) {println(new java.io.File(new java.io.File(arguments[i]).toURI().normalize()))}' $paths
realpathtiene una -sopción para no resuelve los enlaces simbólicos y únicas referencias a resolver /./, /../y retire adicionales /caracteres. Cuando se combina con la -mopción, realpathfunciona solo con el nombre del archivo y no toca ningún archivo real. Que suena como la solución perfecta. Pero, por desgracia, realpathtodavía falta en muchos sistemas.
toxalot
La eliminación de ..componentes no se puede hacer sintácticamente cuando los enlaces simbólicos están involucrados. /one/two/../threeno es lo mismo que /one/threesi fuera twoun enlace simbólico a /foo/bar.
jrw32982 es compatible con Monica el
@ jrw32982 sí, como dije en mi respuesta, esto es para un caso de uso cuando la canonicalización de enlaces simbólicos no es deseada o necesaria.
Jesse Glick
@JesseGlick no se trata solo de si quieres o no canonizar enlaces simbólicos. Su algoritmo en realidad produce la respuesta incorrecta. Para que su respuesta sea correcta, debe saber a priori que no había enlaces simbólicos involucrados (o que solo eran de cierta forma). Su respuesta dice que no desea canonizarlos, no que no haya enlaces simbólicos involucrados en la ruta.
jrw32982 es compatible con Monica el
Hay casos de uso en los que se debe realizar la normalización sin asumir ninguna estructura de directorio fija y existente. La normalización de URI es similar. En estos casos, es una limitación inherente que, en general, el resultado no será correcto si hay enlaces simbólicos cerca de un directorio donde el resultado se aplica más tarde.
Jesse Glick
5
Llego tarde a la fiesta, pero esta es la solución que he creado después de leer un montón de hilos como este:
resolve_dir(){(builtin cd `dirname "${1/#~/$HOME}"`'/'`basename "${1/#~/$HOME}"`2>/dev/null;if[ $?-eq 0];then pwd;fi)}
Esto resolverá la ruta absoluta de $ 1, jugará bien con ~, mantendrá los enlaces simbólicos en la ruta donde están, y no interferirá con su pila de directorios. Devuelve la ruta completa o nada si no existe. Espera que $ 1 sea un directorio y probablemente fallará si no lo es, pero esa es una verificación fácil de hacer usted mismo.
Hablador, y un poco tarde la respuesta. Necesito escribir uno ya que estoy atascado en RHEL4 / 5 anterior. Manejo los enlaces absolutos y relativos, y simplifica las entradas //, /./ y somedir /../.
Pruebe nuestro nuevo producto de biblioteca Bash realpath-lib que hemos colocado en GitHub para uso gratuito y sin gravámenes. Está completamente documentado y es una gran herramienta de aprendizaje.
Resuelve rutas locales, relativas y absolutas y no tiene ninguna dependencia, excepto Bash 4+; por lo que debería funcionar en casi cualquier lugar. Es gratis, limpio, simple e instructivo.
Sin embargo, esto no resuelve los enlaces simbólicos. Realpath procesa rutas que comienzan en la raíz y sigue enlaces simbólicos a medida que avanza. Todo lo que hace es colapsar las referencias principales.
Martijn Pieters
2
Según la respuesta de @ Andre, podría tener una versión un poco mejor, en caso de que alguien busque una solución basada en la manipulación de cadenas completamente libre de bucles. También es útil para aquellos que no desean desreferenciar ningún enlace simbólico, que es la desventaja de usar realpatho readlink -f.
Funciona en versiones bash 3.2.25 y superiores.
shopt -s extglob
normalise_path(){local path="$1"# get rid of /../ example: /one/../two to /two
path="${path//\/*([!\/])\/\.\./}"# get rid of /./ and //* example: /one/.///two to /one/two
path="${path//@(\/\.\/|\/+(\/))//}"# remove the last '/.'
echo "${path%%/.}"}
$ normalise_path /home/codemedic/../codemedic////.config
/home/codemedic/.config
Esta es una buena idea, pero perdí 20 minutos tratando de hacer que esto funcione en varias versiones diferentes de bash. Resulta que la opción de shell extglob necesita estar activada para que esto funcione, y no es por defecto. Cuando se trata de la funcionalidad bash, es importante especificar tanto la versión requerida como las opciones no predeterminadas porque estos detalles pueden variar entre los sistemas operativos. Por ejemplo, una versión reciente de Mac OSX (Yosemite) solo viene con una versión desactualizada de bash (3.2).
drwatsoncode
Lo siento @ricovox; Ahora los he actualizado. Estoy ansioso por saber la versión exacta de Bash que tienes allí. La fórmula anterior (actualizada) funciona en CentOS 5.8 que viene con bash 3.2.25
ϹοδεMεδιϲ
Perdón por la confusion. Este código funcionó en mi versión de Mac OSX bash (3.2.57) una vez que encendí extglob. Mi nota sobre las versiones de bash fue más general (que en realidad se aplica más a otra respuesta aquí con respecto a la expresión regular en bash).
drwatsoncode
2
Aunque aprecio tu respuesta. Lo usé como base para los míos. Por cierto, noté varios casos en los que el suyo falla: (1) Trayectos relativos hello/../world(2) Puntos en el nombre del archivo /hello/..world(3) Puntos después de la doble barra /hello//../world(4) Punto antes o después de la doble barra /hello//./worldo /hello/.//world (5) Principal después de la actual: /hello/./../world/ (6) Principal después de Parent:, /hello/../../worldetc. - Algunos de estos pueden repararse mediante el uso de un bucle para hacer correcciones hasta que la ruta deje de cambiar. (También elimine dir/../, /dir/..pero no elimine dir/..del final.)
drwatsoncode
0
Basado en el excelente fragmento de python de loveborg, escribí esto:
#!/bin/sh# Version of readlink that follows links to the end; good for Mac OS Xfor file in"$@";dowhile[-h "$file"];do
l=`readlink $file`case"$l"in/*) file="$l";;*) file=`dirname "$file"`/"$l"esacdone#echo $file
python -c "import os,sys; print os.path.abspath(sys.argv[1])""$file"done
Aquí hay un breve caso de prueba con algunos espacios retorcidos en las rutas para ejercer completamente la cita
mkdir -p "/tmp/test/ first path "
mkdir -p "/tmp/test/ second path "
echo "hello">"/tmp/test/ first path / red .txt "
ln -s "/tmp/test/ first path / red .txt ""/tmp/test/ second path / green .txt "
cd "/tmp/test/ second path "
fullpath " green .txt "
cat " green .txt "
Sé que esta es una pregunta antigua. Todavía estoy ofreciendo una alternativa. Recientemente me encontré con el mismo problema y no encontré ningún comando portátil y existente para hacerlo. Así que escribí el siguiente script de shell que incluye una función que puede hacer el truco.
#! /bin/sh function normalize {local rc=0local ret
if[ $# -gt 0 ] ; then# invalidif["x`echo $1 | grep -E '^/\.\.'`"!="x"];then
echo $1
return-1fi# convert to absolute pathif["x`echo $1 | grep -E '^\/'`"=="x"];then
normalize "`pwd`/$1"return $?fi
ret=`echo $1 | sed 's;/\.\($\|/\);/;g' | sed 's;/[^/]*[^/.]\+[^/]*/\.\.\($\|/\);/;g'`else
read line
normalize "$line"return $?fiif["x`echo $ret | grep -E '/\.\.?(/|$)'`"!="x"];then
ret=`normalize "$ret"`
rc=$?fi
echo "$ret"return $rc
}
Hice una función integrada solo para manejar esto con un enfoque en el rendimiento más alto posible (por diversión). No resuelve enlaces simbólicos, por lo que es básicamente lo mismo que realpath -sm.
## A bash-only mimic of `realpath -sm`. ## Give it path[s] as argument[s] and it will convert them to clean absolute paths
abspath (){
${*+false}&&{>&2 echo $FUNCNAME: missing operand;return1;};local c s p IFS='/';## path chunk, absolute path, input path, IFS for splitting paths into chunkslocal-i r=0;## return valuefor p in"$@";docase"$p"in## Check for leading backslashes, identify relative/absolute path'')((r|=1));continue;;//[!/]*)>&2 echo "paths =~ ^//[^/]* are impl-defined; not my problem";((r|=2));continue;;/*);;*) p="$PWD/$p";;## Prepend the current directory to form an absolute pathesac
s='';for c in $p;do## Let IFS split the path at '/'scase $c in### NOTE: IFS is '/'; so no quotes needed here''|.);;## Skip duplicate '/'s and '/./'s..) s="${s%/*}";;## Trim the previous addition to the absolute path string*) s+=/$c;;### NOTE: No quotes here intentionally. They make no difference, it seemsesac;done;
echo "${s:-/}";## If xpg_echo is set, use `echo -E` or `printf $'%s\n'` insteaddonereturn $r;}
Nota: Esta función no maneja rutas que comiencen //, ya que exactamente dos barras diagonales dobles al comienzo de una ruta son comportamientos definidos por la implementación. Sin embargo, se maneja /, ///y así sucesivamente.
Esta función parece manejar todos los casos límite correctamente, pero aún puede haber algunos por ahí que no he tratado.
Nota de rendimiento: cuando se llama con miles de argumentos, se abspathejecuta aproximadamente 10 veces más lento que realpath -sm; cuando se llama con un solo argumento, se abspathejecuta> 110 veces más rápido que realpath -smen mi máquina, principalmente debido a que no es necesario ejecutar un nuevo programa cada vez.
la stat -f %N ~/Documentslínea es un arenque rojo ... su caparazón se está reemplazando ~/Documentspor /Users/me/Documents, y statsolo está imprimiendo su argumento literalmente.
/foo/bar
o incluso/foo
existe, o solo le interesa el aspecto de manipulación de cadenas de acuerdo con las reglas de nombre de ruta?/foo/bar/..
a/foo
, y el uso de unbash
comando. Si hay otros requisitos que no están establecidos, entonces quizás deberían ser ...Respuestas:
si desea cortar parte de un nombre de archivo de la ruta, "dirname" y "basename" son sus amigos, y "realpath" también es útil.
realpath
alternativasSi
realpath
su shell no lo admite, puede intentartambién
Funciona igual que
en que el camino no necesita existir para ser normalizado.
fuente
realpath
yreadlink
provienen de las utilidades principales de GNU, por lo que lo más probable es que obtenga ambos o ninguno. Si no recuerdo mal, la versión de readlink en Mac es ligeramente diferente a la de GNU: - \No sé si hay un comando bash directo para hacer esto, pero generalmente lo hago
y funciona bien
fuente
rm -rf $normalDir
) si dirToNormalize no existe!&&
según el comentario de @ DavidBlevins.Tratar
realpath
. A continuación se muestra la fuente en su totalidad, por la presente donada al dominio público.fuente
realpath
. También es mi favorito, pero en lugar de compilar su herramienta desde la fuente. Todo es para peso pesado, y la mayoría de las veces solo quieresreadlink -f
... Por cierto,readlink
tampoco es un bash incorporado, sino parte decoreutils
Ubuntu.Una solución portátil y confiable es usar python, que está preinstalado prácticamente en todas partes (incluido Darwin). Tienes dos opciones:
abspath
devuelve una ruta absoluta pero no resuelve enlaces simbólicos:python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
realpath
devuelve una ruta absoluta y al hacerlo resuelve enlaces simbólicos, generando una ruta canónica:python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
En cada caso,
path/to/file
puede ser una ruta relativa o absoluta.fuente
readlink
está disponible en OS X, solo que no con la-f
opción. Soluciones portátiles discutidas aquí .Use la utilidad readlink del paquete coreutils.
fuente
readlink
es el estándar bash para obtener la ruta absoluta. También tiene la ventaja de devolver cadenas vacías si las rutas o una ruta no existe (dadas las banderas para hacerlo).Para obtener la ruta absoluta a un directorio que puede existir o no, pero los padres de quién existen, use:
Para obtener la ruta absoluta a un directorio que debe existir junto con todos los padres:
Para canonizar la ruta dada y seguir enlaces simbólicos si existen, pero ignorar los directorios que faltan y simplemente devolver la ruta de todos modos, es:
El único inconveniente es que readlink seguirá a los enlaces. Si no desea seguir los enlaces, puede usar esta convención alternativa:
Eso conducirá a la parte del directorio de $ path e imprimirá el directorio actual junto con la parte del archivo de $ path. Si no puede chdir, obtienes una cadena vacía y un error en stderr.
fuente
readlink
Es una buena opción si está disponible. La versión de OS X no admite las opciones-e
o-f
. En los primeros tres ejemplos, debe tener comillas dobles$path
para manejar espacios o comodines en el nombre del archivo. +1 para la expansión de parámetros, pero esto tiene una vulnerabilidad de seguridad. Sipath
está vacío, esto lo harácd
a su directorio de inicio. Necesitas comillas dobles.abspath=$(cd "${path%/*}" && echo "$PWD/${path##*/}")
Antigua pregunta, pero hay una forma mucho más simple si se trata de nombres de ruta completos a nivel de shell:
Como el cd ocurre en una subshell, no afecta el script principal.
Dos variaciones, suponiendo que sus comandos integrados de shell acepten -L y -P, son:
Personalmente, rara vez necesito este enfoque posterior a menos que me fascinen los enlaces simbólicos por alguna razón.
FYI: variación en la obtención del directorio de inicio de un script que funciona incluso si el script cambia su directorio actual más adelante.
El uso de CD asegura que siempre tenga el directorio absoluto, incluso si el script se ejecuta mediante comandos como ./script.sh que, sin el cd / pwd, a menudo da solo ... Inútil si el script hace un cd más adelante.
fuente
Como señaló Adam Liss,
realpath
no se incluye en todas las distribuciones. Lo cual es una pena, porque es la mejor solución. El código fuente proporcionado es excelente, y probablemente comenzaré a usarlo ahora. Esto es lo que he estado usando hasta ahora, que comparto aquí solo para completar:Si usted quiere que los enlaces simbólicos a resolver, simplemente reemplazar
pwd
conpwd -P
.fuente
pwd -P
opción para este caso ... Considere lo que sucedería si$(basename "$1")
fuera un enlace simbólico a un archivo en otro directorio. Elpwd -P
único resuelve enlaces simbólicos en la parte del directorio de la ruta, pero no la parte del nombre base.Mi solución reciente fue:
Basado en la respuesta de Tim Whitcomb.
fuente
pushd $(dirname /usr/bin/java)
intentarlo.No es exactamente una respuesta, sino quizás una pregunta de seguimiento (la pregunta original no era explícita):
readlink
está bien si realmente quieres seguir enlaces simbólicos. Pero también hay un caso de uso por el solo hecho de la normalización./
y../
y//
secuencias, que se pueden hacer puramente sintáctico, sin canonizan enlaces simbólicos.readlink
no es bueno para esto, y tampoco lo esrealpath
.funciona para caminos existentes, pero se rompe para otros.
Una
sed
secuencia de comandos parecería ser una buena apuesta, excepto que no puede reemplazar iterativamente secuencias (/foo/bar/baz/../..
->/foo/bar/..
->/foo
) sin usar algo como Perl, que no es seguro asumir en todos los sistemas, o usar algún bucle feo para comparar la salida desed
a su entradaFWIW, una línea usando Java (JDK 6+):
fuente
realpath
tiene una-s
opción para no resuelve los enlaces simbólicos y únicas referencias a resolver/./
,/../
y retire adicionales/
caracteres. Cuando se combina con la-m
opción,realpath
funciona solo con el nombre del archivo y no toca ningún archivo real. Que suena como la solución perfecta. Pero, por desgracia,realpath
todavía falta en muchos sistemas...
componentes no se puede hacer sintácticamente cuando los enlaces simbólicos están involucrados./one/two/../three
no es lo mismo que/one/three
si fueratwo
un enlace simbólico a/foo/bar
.Llego tarde a la fiesta, pero esta es la solución que he creado después de leer un montón de hilos como este:
Esto resolverá la ruta absoluta de $ 1, jugará bien con ~, mantendrá los enlaces simbólicos en la ruta donde están, y no interferirá con su pila de directorios. Devuelve la ruta completa o nada si no existe. Espera que $ 1 sea un directorio y probablemente fallará si no lo es, pero esa es una verificación fácil de hacer usted mismo.
fuente
Hablador, y un poco tarde la respuesta. Necesito escribir uno ya que estoy atascado en RHEL4 / 5 anterior. Manejo los enlaces absolutos y relativos, y simplifica las entradas //, /./ y somedir /../.
fuente
Pruebe nuestro nuevo producto de biblioteca Bash realpath-lib que hemos colocado en GitHub para uso gratuito y sin gravámenes. Está completamente documentado y es una gran herramienta de aprendizaje.
Resuelve rutas locales, relativas y absolutas y no tiene ninguna dependencia, excepto Bash 4+; por lo que debería funcionar en casi cualquier lugar. Es gratis, limpio, simple e instructivo.
Tu puedes hacer:
Esta función es el núcleo de la biblioteca:
También contiene funciones para get_dirname, get_filename, get_ stemname y validate_path. Pruébelo en todas las plataformas y ayude a mejorarlo.
fuente
El problema
realpath
es que no está disponible en BSD (u OSX para el caso). Aquí hay una receta simple extraída de un artículo bastante antiguo (2009) de Linux Journal , que es bastante portátil:Observe esta variante tampoco no requiere la trayectoria de existir.
fuente
Según la respuesta de @ Andre, podría tener una versión un poco mejor, en caso de que alguien busque una solución basada en la manipulación de cadenas completamente libre de bucles. También es útil para aquellos que no desean desreferenciar ningún enlace simbólico, que es la desventaja de usar
realpath
oreadlink -f
.Funciona en versiones bash 3.2.25 y superiores.
fuente
hello/../world
(2) Puntos en el nombre del archivo/hello/..world
(3) Puntos después de la doble barra/hello//../world
(4) Punto antes o después de la doble barra/hello//./world
o/hello/.//world
(5) Principal después de la actual:/hello/./../world/
(6) Principal después de Parent:,/hello/../../world
etc. - Algunos de estos pueden repararse mediante el uso de un bucle para hacer correcciones hasta que la ruta deje de cambiar. (También eliminedir/../
,/dir/..
pero no eliminedir/..
del final.)Basado en el excelente fragmento de python de loveborg, escribí esto:
fuente
Esto funciona incluso si el archivo no existe. Requiere que exista el directorio que contiene el archivo.
fuente
realpath -e
Necesitaba una solución que hiciera las tres cosas:
realpath
yreadlink -f
son complementosNinguna de las respuestas tenía tanto # 1 como # 2. Agregué el n. ° 3 para salvar a los demás.
Aquí hay un breve caso de prueba con algunos espacios retorcidos en las rutas para ejercer completamente la cita
fuente
Sé que esta es una pregunta antigua. Todavía estoy ofreciendo una alternativa. Recientemente me encontré con el mismo problema y no encontré ningún comando portátil y existente para hacerlo. Así que escribí el siguiente script de shell que incluye una función que puede hacer el truco.
https://gist.github.com/bestofsong/8830bdf3e5eb9461d27313c3c282868c
fuente
Hice una función integrada solo para manejar esto con un enfoque en el rendimiento más alto posible (por diversión). No resuelve enlaces simbólicos, por lo que es básicamente lo mismo que
realpath -sm
.Nota: Esta función no maneja rutas que comiencen
//
, ya que exactamente dos barras diagonales dobles al comienzo de una ruta son comportamientos definidos por la implementación. Sin embargo, se maneja/
,///
y así sucesivamente.Esta función parece manejar todos los casos límite correctamente, pero aún puede haber algunos por ahí que no he tratado.
Nota de rendimiento: cuando se llama con miles de argumentos, se
abspath
ejecuta aproximadamente 10 veces más lento querealpath -sm
; cuando se llama con un solo argumento, seabspath
ejecuta> 110 veces más rápido querealpath -sm
en mi máquina, principalmente debido a que no es necesario ejecutar un nuevo programa cada vez.fuente
Hoy descubrí que puedes usar el
stat
comando para resolver rutas.Entonces, para un directorio como "~ / Documentos":
Puedes ejecutar esto:
stat -f %N ~/Documents
Para obtener el camino completo:
/Users/me/Documents
Para enlaces simbólicos, puede usar la opción de formato% Y:
stat -f %Y example_symlink
Lo que podría devolver un resultado como:
/usr/local/sbin/example_symlink
Las opciones de formato pueden ser diferentes en otras versiones de * NIX, pero me han funcionado en OSX.
fuente
stat -f %N ~/Documents
línea es un arenque rojo ... su caparazón se está reemplazando~/Documents
por/Users/me/Documents
, ystat
solo está imprimiendo su argumento literalmente.Una solución simple usando
node.js
:fuente