bash - saber - ruta absoluta y relativa linux
Bash: recupera la ruta absoluta dada relativa (15)
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.
¿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
De manera similar a la respuesta de @ ernest-a, pero sin afectar $OLDPWD
o definir una nueva función, podría $OLDPWD
una subshell (cd <path>; pwd)
$ pwd
/etc/apache2
$ cd ../cups
$ cd -
/etc/apache2
$ (cd ~/..; pwd)
/Users
$ cd -
/etc/cups
En caso de find
, probablemente sea más fácil dar la ruta absoluta para buscar, por ejemplo:
find /etc
find `pwd`/subdir_of_current_dir/ -type f
La respuesta de Eugen no funcionó para mí, pero lo hizo:
absolute="$(cd $(dirname $file); pwd)/$(basename $file)"
Nota al margen, su directorio de trabajo actual no se ve afectado.
Lo que dijeron, excepto find $PWD
o (en bash) find ~+
es un poco más conveniente.
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 OSX antes de llegar al desbordamiento de la pila. Estoy seguro de que está ahí fuera.
En Linux puede usar readlink -e
en tándem con dirname
.
$(dirname $(readlink -e ../../../../etc/passwd))
rendimientos
/etc/
Y luego usa la hermana de dirname
, basename
para obtener el nombre de 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, el basename
arrojará nada y terminarás con doble barra en el resultado final.
Prueba realpath
.
~ $ sudo apt-get install realpath
~ $ realpath .bashrc
/home/username/.bashrc
La respuesta viene de " comando bash / fish para imprimir la ruta absoluta a un archivo ".
Si desea transformar una variable que contiene una ruta relativa en una ruta absoluta, esto funciona:
dir=`cd "$dir"`
"cd" se repite sin cambiar el directorio de trabajo, porque se ejecuta aquí en un subconjunto.
Si está utilizando bash en Mac OS X que no tiene realpath ni su readlink puede imprimir la ruta absoluta, puede tener otra opción que codificar su propia versión para imprimirla. Aquí está mi implementación:
(puro bash)
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[*]}"
)
}
(use 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
Si tiene instalado el paquete coreutils, generalmente puede usar readlink -f relative_file_name
para recuperar el absoluto (con todos los enlaces simbólicos resueltos)
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)
realpath
es probablemente el mejor
Pero ...
La pregunta inicial fue muy confusa para empezar, con un ejemplo poco relacionado con la pregunta tal como se establece.
La respuesta seleccionada en realidad responde al ejemplo dado, y no a la pregunta en el título. El primer comando es esa respuesta (¿es realmente ?, lo dudo), y podría funcionar tan bien sin el ''/''. Y no puedo ver qué está haciendo el segundo comando.
Varios problemas son mixtos:
cambiando un nombre de ruta relativo a uno absoluto, lo que sea que denota, posiblemente nada. ( Por lo general, si emite un comando como
touch foo/bar
, el nombre de rutafoo/bar
debe existir para usted, y posiblemente se use en el cálculo, antes de que realmente se cree el archivo ) .puede haber varios nombres de ruta absolutos que denotan el mismo archivo (o posible archivo), especialmente debido a enlaces simbólicos (enlaces simbólicos) en la ruta, pero posiblemente por otros motivos (un dispositivo puede montarse dos veces como de solo lectura). Uno puede o no querer resolver explícitamente tales enlaces simbólicos.
llegar al final de una cadena de enlaces simbólicos a un archivo o nombre que no es un enlace simbólico. Esto puede generar o no un nombre de ruta absoluto, dependiendo de cómo se hace. Y uno puede, o no, querer resolverlo en una ruta de acceso absoluta.
El comando readlink foo
without option 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 de enlace simbólico.
Sin embargo, readlink
tiene opciones (-f -e o -m) que funcionarán para todos los archivos, y dan una ruta de acceso absoluta (la 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 una ruta de acceso absoluta sin resolver los enlaces simbólicos intermedios en la ruta. Esto se hace mediante el comando realpath -s foo
En el caso de un argumento de enlace simbólico, readlink
con sus opciones resolverá nuevamente todos los enlaces simbólicos en la ruta absoluta al argumento, pero eso también incluirá todos los enlaces simbólicos que puedan encontrarse al seguir el valor del argumento. Puede que no lo desee si desea una ruta de acceso absoluta al enlace simbólico en sí mismo, en lugar de a lo que pueda vincularse. Nuevamente, si foo
es un enlace simbólico, realpath -s foo
obtendrá una ruta absoluta sin resolver los enlaces simbólicos, incluido el que se da como argumento.
Sin la opción -s
, realpath
hace casi lo mismo que readlink
, excepto simplemente leyendo 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 en los sistemas.
Conclusión: realpath
es el mejor comando para usar, con la mayor flexibilidad, al menos para el uso que se solicita aquí.
#! /bin/sh
echo "$(cd "$(dirname "$1")"; pwd)/$(basename "$1")"
UPD Algunas explicaciones
- Este script obtiene ruta relativa como argumento
"$1"
- Luego, obtenemos el nombre del directorio como parte de esa ruta (puede pasar el directorio o el archivo a este script):
dirname "$1"
- Luego,
cd "$(dirname "$1")
en este directorio relativo y obtenemos una ruta absoluta ejecutando el comandopwd
shell - Después de eso, agregamos basename a la ruta absoluta:
$(basename "$1")
- Como paso final lo hacemos
echo
echo "mydir/doc/ mydir/usoe ./mydir/usm" | awk ''{ split($0,array," "); for(i in array){ system("cd "array[i]" && echo $PWD") } }''