¿Hay un comando para recuperar la ruta absoluta dada la ruta relativa?
Por ejemplo, quiero que $ line contenga la ruta absoluta de cada archivo en dir ./etc/
find ./ -type f | while read line; do
echo $line
done
¿Hay un comando para recuperar la ruta absoluta dada la ruta relativa?
Por ejemplo, quiero que $ line contenga la ruta absoluta de cada archivo en dir ./etc/
find ./ -type f | while read line; do
echo $line
done
Respuestas:
utilizar:
find "$(pwd)"/ -type f
para obtener todos los archivos o
echo "$(pwd)/$line"
para mostrar la ruta completa (si la ruta relativa es importante)
$(pwd)
en lugar de $PWD
? (sí, sé que pwd
es una construcción)
Tratar realpath
.
~ $ sudo apt-get install realpath # may already be installed
~ $ realpath .bashrc
/home/username/.bashrc
Para evitar expandir los enlaces simbólicos, use realpath -s
.
La respuesta proviene del " comando bash / fish para imprimir la ruta absoluta a un archivo ".
realpath
no parece estar disponible en Mac (OS X 10.11 "El Capitan"). :-(
realpath
tampoco parece estar disponible en CentOS 6
brew install coreutils
traerárealpath
realpath
ya está presente. No tuve que instalarlo por separado.
realpath
está disponible en Git para Windows (para mí, al menos).
Si tiene instalado el paquete coreutils, generalmente puede usarlo readlink -f relative_file_name
para recuperar el absoluto (con todos los enlaces simbólicos resueltos)
brew install coreutils
. Sin embargo, el ejecutable está precedido por ag:greadlink -f relative_file_name
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD Algunas explicaciones
"$1"
dirname "$1"
cd "$(dirname "$1")
en este directorio relativo y obtenemos la ruta absoluta al ejecutarlopwd
comando de shell$(basename "$1")
echo
serealpath
o readlink -f
hacer. Por ejemplo, no funciona en rutas donde el último componente es un enlace simbólico.
-P
opción de pwd
comando:echo "$(cd "$(dirname "$1")"; pwd -P)/$(basename "$1")"
Por lo que vale, voté por la respuesta que se eligió, pero quería compartir una solución. La desventaja es que solo es Linux: pasé unos 5 minutos tratando de encontrar el equivalente de OSX antes de llegar al desbordamiento de Stack. Sin embargo, estoy seguro de que está ahí afuera.
En Linux puedes usarlo readlink -e
en conjunto con dirname
.
$(dirname $(readlink -e ../../../../etc/passwd))
rendimientos
/etc/
Y luego usas dirname
la hermana de, basename
para obtener el nombre del archivo
$(basename ../../../../../passwd)
rendimientos
passwd
Ponlo todo junto..
F=../../../../../etc/passwd
echo "$(dirname $(readlink -e $F))/$(basename $F)"
rendimientos
/etc/passwd
Estás seguro si estás apuntando a un directorio, basename
no devolverás nada y terminarás con dos barras diagonales en la salida final.
dirname
, readlink
y basename
. Eso me ayudó a obtener el camino absoluto de un enlace simbólico, no su objetivo.
/home/GKFX
y touch newfile
escribo, entonces antes de presionar enter, podría resolver que me refiero a "crear / inicio / GKFX / newfile", que es una ruta absoluta a un archivo que aún no existe.
Creo que este es el más portátil:
abspath() {
cd "$(dirname "$1")"
printf "%s/%s\n" "$(pwd)" "$(basename "$1")"
cd "$OLDPWD"
}
Sin embargo, fallará si la ruta no existe.
dirname
es una utilidad central de GNU, no es común a todos los unixen, creo.
dirname
es una utilidad estándar POSIX, vea aquí: pubs.opengroup.org/onlinepubs/9699919799/utilities/dirname.html
${1##*/}
por un día, y ahora que reemplacé esa basura basename "$1"
parece que finalmente está manejando adecuadamente las rutas que terminan en /.
../..
realpath
es probablemente el mejor
Pero ...
La pregunta inicial fue muy confusa para comenzar, con un ejemplo mal relacionado con la pregunta como se indicó.
La respuesta seleccionada en realidad responde al ejemplo dado, y en absoluto a la pregunta en el título. El primer comando es esa respuesta (¿es realmente? Dudo), y podría funcionar también sin el '/'. Y no veo qué hace el segundo comando.
Varios problemas son mixtos:
cambiando un nombre de ruta relativo en uno absoluto, lo que sea que denote, posiblemente nada. ( Normalmente, si emite un comando como touch foo/bar
, el nombre de ruta foo/bar
debe existir para usted, y posiblemente debe usarse en el cálculo, antes de que el archivo se cree realmente ) .
puede haber varios nombres de ruta absolutos que denotan el mismo archivo (o archivo potencial), especialmente debido a enlaces simbólicos (enlaces simbólicos) en la ruta, pero posiblemente por otras razones (un dispositivo puede montarse dos veces como de solo lectura). Uno puede o no querer resolver explícitamente dichos enlaces simbólicos.
llegar al final de una cadena de enlaces simbólicos a un archivo o nombre sin enlace simbólico. Esto puede o no producir un nombre de ruta absoluto, dependiendo de cómo se haga. Y uno puede o no querer resolverlo en una ruta absoluta.
El comando readlink foo
sin opción da una respuesta solo si su argumento foo
es un enlace simbólico, y esa respuesta es el valor de ese enlace simbólico. No se sigue ningún otro enlace. La respuesta puede ser una ruta relativa: cualquiera que sea el valor del argumento del enlace simbólico.
Sin embargo, readlink
tiene opciones (-f -e o -m) que funcionarán para todos los archivos y le darán un nombre de ruta absoluto (el que no tiene enlaces simbólicos) al archivo realmente denotado por el argumento.
Esto funciona bien para cualquier cosa que no sea un enlace simbólico, aunque uno podría desear usar un nombre de ruta absoluto sin resolver los enlaces simbólicos intermedios en la ruta. Esto lo hace el comandorealpath -s foo
En el caso de un argumento de enlace simbólico, readlink
con sus opciones volverá a resolver todos los enlaces simbólicos en la ruta absoluta al argumento, pero eso también incluirá todos los enlaces simbólicos que puedan encontrarse siguiendo el valor del argumento. Es posible que no desee eso si desea una ruta absoluta al enlace simbólico del argumento en sí mismo, en lugar de a lo que sea que lo vincule. Nuevamente, si foo
es un enlace simbólico, realpath -s foo
obtendrá una ruta absoluta sin resolver enlaces simbólicos, incluido el que se proporciona como argumento.
Sin la -s
opción, realpath
hace más o menos lo mismo que
readlink
, excepto simplemente leer el valor de un enlace, así como varias otras cosas. Simplemente no está claro para mí por qué readlink
tiene sus opciones, creando aparentemente una redundancia indeseable con
realpath
.
Explorar la web no dice mucho más, excepto que puede haber algunas variaciones entre los sistemas.
Conclusión: realpath
es el mejor comando para usar, con la mayor flexibilidad, al menos para el uso solicitado aquí.
Mi solución favorita fue la de @EugenKonkov porque no implicaba la presencia de otras utilidades (el paquete coreutils).
Pero falló para las rutas relativas "." y "..", así que aquí hay una versión ligeramente mejorada que maneja estos casos especiales.
Sin embargo, todavía falla si el usuario no tiene permiso para cd
ingresar al directorio principal de la ruta relativa.
#! /bin/sh
# Takes a path argument and returns it as an absolute path.
# No-op if the path is already absolute.
function to-abs-path {
local target="$1"
if [ "$target" == "." ]; then
echo "$(pwd)"
elif [ "$target" == ".." ]; then
echo "$(dirname "$(pwd)")"
else
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
fi
}
La respuesta de Eugen no funcionó para mí, pero esto sí:
absolute="$(cd $(dirname \"$file\"); pwd)/$(basename \"$file\")"
Nota al margen, su directorio de trabajo actual no se ve afectado.
La mejor solución, en mi opinión, es la publicada aquí: https://stackoverflow.com/a/3373298/9724628 .
Requiere python para funcionar, pero parece cubrir todos o la mayoría de los casos extremos y ser una solución muy portátil.
python -c "import os,sys; print(os.path.realpath(sys.argv[1]))" path/to/file
python -c "import os,sys; print(os.path.abspath(sys.argv[1]))" path/to/file
Si está utilizando bash en Mac OS X que ni ha existido realpath ni su enlace de lectura puede imprimir la ruta absoluta, puede tener la opción de codificar su propia versión para imprimirla. Aquí está mi implementación:
(puro golpe)
abspath(){
local thePath
if [[ ! "$1" =~ ^/ ]];then
thePath="$PWD/$1"
else
thePath="$1"
fi
echo "$thePath"|(
IFS=/
read -a parr
declare -a outp
for i in "${parr[@]}";do
case "$i" in
''|.) continue ;;
..)
len=${#outp[@]}
if ((len==0));then
continue
else
unset outp[$((len-1))]
fi
;;
*)
len=${#outp[@]}
outp[$len]="$i"
;;
esac
done
echo /"${outp[*]}"
)
}
(usa gawk)
abspath_gawk() {
if [[ -n "$1" ]];then
echo $1|gawk '{
if(substr($0,1,1) != "/"){
path = ENVIRON["PWD"]"/"$0
} else path = $0
split(path, a, "/")
n = asorti(a, b,"@ind_num_asc")
for(i in a){
if(a[i]=="" || a[i]=="."){
delete a[i]
}
}
n = asorti(a, b, "@ind_num_asc")
m = 0
while(m!=n){
m = n
for(i=1;i<=n;i++){
if(a[b[i]]==".."){
if(b[i-1] in a){
delete a[b[i-1]]
delete a[b[i]]
n = asorti(a, b, "@ind_num_asc")
break
} else exit 1
}
}
}
n = asorti(a, b, "@ind_num_asc")
if(n==0){
printf "/"
} else {
for(i=1;i<=n;i++){
printf "/"a[b[i]]
}
}
}'
fi
}
(puro bsd awk)
#!/usr/bin/env awk -f
function abspath(path, i,j,n,a,b,back,out){
if(substr(path,1,1) != "/"){
path = ENVIRON["PWD"]"/"path
}
split(path, a, "/")
n = length(a)
for(i=1;i<=n;i++){
if(a[i]==""||a[i]=="."){
continue
}
a[++j]=a[i]
}
for(i=j+1;i<=n;i++){
delete a[i]
}
j=0
for(i=length(a);i>=1;i--){
if(back==0){
if(a[i]==".."){
back++
continue
} else {
b[++j]=a[i]
}
} else {
if(a[i]==".."){
back++
continue
} else {
back--
continue
}
}
}
if(length(b)==0){
return "/"
} else {
for(i=length(b);i>=1;i--){
out=out"/"b[i]
}
return out
}
}
BEGIN{
if(ARGC>1){
for(k=1;k<ARGC;k++){
print abspath(ARGV[k])
}
exit
}
}
{
print abspath($0)
}
ejemplo:
$ abspath I/am/.//..//the/./god/../of///.././war
/Users/leon/I/the/war
Si la ruta relativa es una ruta de directorio, entonces prueba la mía, debería ser la mejor:
absPath=$(pushd ../SOME_RELATIVE_PATH_TO_Directory > /dev/null && pwd && popd > /dev/null)
echo $absPath
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk '{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }'
Una mejora a la versión bastante agradable de @ ernest-a:
absolute_path() {
cd "$(dirname "$1")"
case $(basename $1) in
..) echo "$(dirname $(pwd))";;
.) echo "$(pwd)";;
*) echo "$(pwd)/$(basename $1)";;
esac
}
Esto trata correctamente con el caso donde se encuentra el último elemento de la ruta ..
, en cuyo caso la "$(pwd)/$(basename "$1")"
respuesta de in @ ernest-a aparecerá como accurate_sub_path/spurious_subdirectory/..
.
Si desea transformar una variable que contiene una ruta relativa en una absoluta, esto funciona:
dir=`cd "$dir"`
"cd" hace eco sin cambiar el directorio de trabajo, porque se ejecuta aquí en un sub-shell.
dir=`cd ".."` && echo $dir
Esta es una solución encadenada de todas las demás, por ejemplo, cuando realpath
falla, ya sea porque no está instalada o porque sale con un código de error, entonces, la siguiente solución se intenta hasta que se obtiene el camino correcto.
#!/bin/bash
function getabsolutepath() {
local target;
local changedir;
local basedir;
local firstattempt;
target="${1}";
if [ "$target" == "." ];
then
printf "%s" "$(pwd)";
elif [ "$target" == ".." ];
then
printf "%s" "$(dirname "$(pwd)")";
else
changedir="$(dirname "${target}")" && basedir="$(basename "${target}")" && firstattempt="$(cd "${changedir}" && pwd)" && printf "%s/%s" "${firstattempt}" "${basedir}" && return 0;
firstattempt="$(readlink -f "${target}")" && printf "%s" "${firstattempt}" && return 0;
firstattempt="$(realpath "${target}")" && printf "%s" "${firstattempt}" && return 0;
# If everything fails... TRHOW PYTHON ON IT!!!
local fullpath;
local pythoninterpreter;
local pythonexecutables;
local pythonlocations;
pythoninterpreter="python";
declare -a pythonlocations=("/usr/bin" "/bin");
declare -a pythonexecutables=("python" "python2" "python3");
for path in "${pythonlocations[@]}";
do
for executable in "${pythonexecutables[@]}";
do
fullpath="${path}/${executable}";
if [[ -f "${fullpath}" ]];
then
# printf "Found ${fullpath}\\n";
pythoninterpreter="${fullpath}";
break;
fi;
done;
if [[ "${pythoninterpreter}" != "python" ]];
then
# printf "Breaking... ${pythoninterpreter}\\n"
break;
fi;
done;
firstattempt="$(${pythoninterpreter} -c "import os, sys; print( os.path.abspath( sys.argv[1] ) );" "${target}")" && printf "%s" "${firstattempt}" && return 0;
# printf "Error: Could not determine the absolute path!\\n";
return 1;
fi
}
printf "\\nResults:\\n%s\\nExit: %s\\n" "$(getabsolutepath "./asdfasdf/ asdfasdf")" "${?}"
Puede usar la sustitución de cadena bash para cualquier ruta relativa $ line:
line=$(echo ${line/#..\//`cd ..; pwd`\/})
line=$(echo ${line/#.\//`pwd`\/})
echo $line
La sustitución básica de la parte delantera de la cadena sigue la fórmula
$ {string / # substring / replace},
que se trata bien aquí: https://www.tldp.org/LDP/abs/html/string-manipulation.html
El \
carácter niega /
cuando queremos que sea parte de la cadena que encontramos / reemplazamos.
No pude encontrar una solución que fuera perfectamente portátil entre Mac OS Catalina, Ubuntu 16 y Centos 7, así que decidí hacerlo con Python en línea y funcionó bien para mis scripts de bash.
to_abs_path() {
python -c "import os; print os.path.abspath('$1')"
}
to_abs_path "/some_path/../secrets"