perl - rutas - Convirtiendo ruta relativa en ruta absoluta?
rutas relativas arcgis (6)
Usando bash
# Directory
relative_dir="folder/subfolder/"
absolute_dir="$( cd "$relative_dir" && pwd )"
# File
relative_file="folder/subfolder/file"
absolute_file="$( cd "${relative_file%/*}" && pwd )"/"${relative_file##*/}"
-
${relative_file%/*}
es el mismo resultado quedirname "$relative_file"
-
${relative_file##*/}
es el mismo resultado que elbasename "$relative_file"
Advertencias : No resuelve enlaces simbólicos (es decir, no canonicaliza la ruta) => No puede diferenciar todos los duplicados si usa enlaces simbólicos.
Usando realpath
Command realpath
hace el trabajo. Una alternativa es usar readlink -e
(o readlink -f
). Sin embargo, realpath
no suele estar instalado por defecto. Si no puede estar seguro de que realpath
o readlink
están presentes, puede sustituirlo utilizando perl (consulte a continuación).
Usando perl
Steven Kramer propone un alias de shell si realpath
no está disponible en su sistema:
$ alias realpath="perl -MCwd -e ''print Cwd::realpath(/$ARGV[0]),qq</n>''"
$ realpath path/folder/file
/home/user/absolute/path/folder/file
o si prefiere usar perl directamente:
$ perl -MCwd -e ''print Cwd::realpath($ARGV[0]),qq</n>'' path/folder/file
/home/user/absolute/path/folder/file
Este comando de una línea perl utiliza Cwd::realpath
. De hecho, hay tres funciones perl. Toman un solo argumento y devuelven el nombre de ruta absoluto. Los detalles a continuación son de la documentación Perl5> Módulos principales> Cwd .
abs_path()
usa el mismo algoritmo quegetcwd()
. Los enlaces simbólicos y los componentes de la ruta relativa (.
Y..
) se resuelven para devolver el nombre de ruta canónico, al igual que en elrealpath
.use Cwd ''abs_path''; my $abs_path = abs_path($file);
realpath()
es un sinónimo deabs_path()
use Cwd ''realpath''; my $abs_path = realpath($file);
fast_abs_path()
es una versión más peligrosa, pero potencialmente más rápida deabs_path()
use Cwd ''fast_abs_path''; my $abs_path = fast_abs_path($file);
Estas funciones se exportan solo en request =>, por lo tanto, use Cwd
para evitar el error de "subrutina no arielf " como se arielf por arielf . Si desea importar todas estas tres funciones, puede usar una línea use Cwd
un solo use Cwd
:
use Cwd qw(abs_path realpath fast_abs_path);
No estoy seguro si estas rutas son duplicadas. Dada la ruta relativa, ¿cómo puedo determinar la ruta absoluta usando un script de shell?
Ejemplo:
relative path: /x/y/../../a/b/z/../c/d
absolute path: /a/b/c/d
Como me he encontrado con esto muchas veces a lo largo de los años, y esta vez necesitaba una versión portátil de bash pura que pudiera usar en OSX y Linux, continué y escribí una:
La versión viva vive aquí:
https://github.com/keen99/shell-functions/tree/master/resolve_path
pero por el bien de SO, aquí está la versión actual (creo que está bien probado ... ¡pero estoy abierto a comentarios!)
Puede que no sea difícil hacer que funcione para bourne shell (sh), pero no lo intenté ... me gusta demasiado $ FUNCNAME. :)
#!/bin/bash
resolve_path() {
#I''m bash only, please!
# usage: resolve_path <a file or directory>
# follows symlinks and relative paths, returns a full real path
#
local owd="$PWD"
#echo "$FUNCNAME for $1" >&2
local opath="$1"
local npath=""
local obase=$(basename "$opath")
local odir=$(dirname "$opath")
if [[ -L "$opath" ]]
then
#it''s a link.
#file or directory, we want to cd into it''s dir
cd $odir
#then extract where the link points.
npath=$(readlink "$obase")
#have to -L BEFORE we -f, because -f includes -L :(
if [[ -L $npath ]]
then
#the link points to another symlink, so go follow that.
resolve_path "$npath"
#and finish out early, we''re done.
return $?
#done
elif [[ -f $npath ]]
#the link points to a file.
then
#get the dir for the new file
nbase=$(basename $npath)
npath=$(dirname $npath)
cd "$npath"
ndir=$(pwd -P)
retval=0
#done
elif [[ -d $npath ]]
then
#the link points to a directory.
cd "$npath"
ndir=$(pwd -P)
retval=0
#done
else
echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2
echo "opath [[ $opath ]]" >&2
echo "npath [[ $npath ]]" >&2
return 1
fi
else
if ! [[ -e "$opath" ]]
then
echo "$FUNCNAME: $opath: No such file or directory" >&2
return 1
#and break early
elif [[ -d "$opath" ]]
then
cd "$opath"
ndir=$(pwd -P)
retval=0
#done
elif [[ -f "$opath" ]]
then
cd $odir
ndir=$(pwd -P)
nbase=$(basename "$opath")
retval=0
#done
else
echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2
echo "opath [[ $opath ]]" >&2
return 1
fi
fi
#now assemble our output
echo -n "$ndir"
if [[ "x${nbase:=}" != "x" ]]
then
echo "/$nbase"
else
echo
fi
#now return to where we were
cd "$owd"
return $retval
}
he aquí un ejemplo clásico, gracias a brew:
%% ls -l `which mvn`
lrwxr-xr-x 1 draistrick 502 29 Dec 17 10:50 /usr/local/bin/mvn@ -> ../Cellar/maven/3.2.3/bin/mvn
usa esta función y devolverá la ruta real -real:
%% cat test.sh
#!/bin/bash
. resolve_path.inc
echo
echo "relative symlinked path:"
which mvn
echo
echo "and the real path:"
resolve_path `which mvn`
%% test.sh
relative symlinked path:
/usr/local/bin/mvn
and the real path:
/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn
De esta fuente viene:
#!/bin/bash
# Assume parameter passed in is a relative path to a directory.
# For brevity, we won''t do argument type or length checking.
ABS_PATH=`cd "$1"; pwd` # double quotes for paths that contain spaces etc...
echo "Absolute path: $ABS_PATH"
También puede hacer un trazador de líneas Perl, por ejemplo, usando Cwd::abs_path
Echa un vistazo a ''realpath''.
$ realpath
usage: realpath [-q] path [...]
$ realpath ../../../../../
/data/home
El método más confiable que he encontrado en Unix es readlink -f
:
$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d
Un par de advertencias:
- Esto también tiene el efecto secundario de resolver todos los enlaces simbólicos. Esto puede o no ser deseable, pero generalmente lo es.
-
readlink
dará un resultado en blanco si hace referencia a un directorio no existente. Si desea admitir rutas que no existen, utilicereadlink -m
lugar. Lamentablemente, esta opción no existe en versiones de readlink publicadas antes de ~ 2005.
Puede ser que esto ayude:
$path = "~user/dir/../file"
$resolvedPath = glob($path); # (To resolve paths with ''~'')
# Since glob does not resolve relative path, we use abs_path
$absPath = abs_path($path);