Convertir ruta relativa a ruta absoluta sin enlace simbólico


63

¿Existe un comando Unix para obtener la ruta absoluta (y canonicalizada) de una ruta relativa que puede contener enlaces simbólicos?

Respuestas:


80

Puede usar la readlinkutilidad, con la -fopción:

-f, --canonicalize

      canonicalize  by  following  every symlink in every component of
      the given name recursively; all  but  the  last  component  must
      exist

Algunas distribuciones, por ejemplo aquellas que usan GNU coreutils y FreeBSD , también vienen con una realpath(1)utilidad que básicamente solo llama realpath(3)y hace casi lo mismo.


17
El -finterruptor no existe en Mac OS X (al menos a partir de 10.8.5). Sin el -finterruptor, solo devuelve un código de error.
iconoclasta

44
Algunos sistemas vienen con ninguno readlink, ni realpath- Solaris y HP-UX, en particular.
Sildoreth

Para el problema de Mac: brew install coreutils apple.stackexchange.com/a/69332/23040 , y si no desea realizar el paso que redirige todas las herramientas CLI estándar de Mac a los equivalentes GNU recién instalados, simplemente llame greadlink.
Adrian

19

Portablemente, el shell establece la PWDvariable en una ubicación absoluta del directorio actual. Cualquier componente de esa ruta puede ser un enlace simbólico.

case $f in
  /*) absolute=$f;;
  *) absolute=$PWD/$f;;
esac

Si desea eliminar .y ..también, cambie al directorio que contiene el archivo y obtenga $PWDallí:

if [ -d "$f" ]; then f=$f/.; fi
absolute=$(cd "$(dirname -- "$f")"; printf %s. "$PWD")
absolute=${absolute%?}
absolute=$absolute/${f##*/}

No hay una forma portátil de seguir enlaces simbólicos. Si tiene una ruta a un directorio, en la mayoría de los dispositivos $(cd -- "$dir" && pwd -P 2>/dev/null || pwd)proporciona una ruta que no usa enlaces simbólicos, porque los shells que rastrean enlaces simbólicos tienden a implementarse pwd -P("P" para "físico").

Algunas unidades proporcionan una utilidad para imprimir la ruta "física" a un archivo.

  • Los sistemas Linux razonablemente recientes (con GNU coreutils o BusyBox) tienen readlink -f, al igual que FreeBSD ≥8.3, NetBSD ≥4.0 y OpenBSD desde 2.2.
  • FreeBSD ≥4.3 tiene realpath(también está presente en algunos sistemas Linux, y está en BusyBox).
  • Si Perl está disponible, puede usar el Cwdmódulo .

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file

¿Por qué pones algo en pwd( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd))? No parece importarle el stdin.
Mateusz Piotrowski

1
@MateuszPiotrowski Typo, quería escribir||
Gilles 'SO- deja de ser malvado'

5

¿Es pwdadecuado para sus necesidades? Da la ruta absoluta del directorio actual. O tal vez lo que quieres es realpath () .


3

alistery rss67en este artículo presentamos la forma más estable, compatible y fácil. Nunca había visto una mejor manera que esta antes.

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`

Si desea volver a la ubicación original,

ORGPATH=`pwd`
RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd $ORGPATH

o

RELPATH=./../
cd $RELPATH
ABSPATH=`pwd`
cd -

Deseo que esto ayude. Esta fue la mejor solución para mí.


12
En realidad, esa no es una buena manera. Cambiar de directorio y volver a ingresar no es confiable: es posible que no tenga permiso para regresar o que el directorio haya cambiado de nombre mientras tanto. En su lugar, cambiar de directorio en un subnivel: ABSPATH=$(cd -- "$RELPATH" && pwd). Tenga en cuenta las comillas dobles alrededor de la sustitución (para no romper si la ruta contiene espacios en blanco y caracteres globales) y la --(en caso de que la ruta comience con -). Además, esto solo funciona para directorios, y no canonicaliza enlaces simbólicos según lo solicitado. Vea mi respuesta para más detalles.
Gilles 'SO- deja de ser malvado'

"> es posible que no tenga el permiso para volver" ¿Quiere decir cd a un directorio pero no puede regresarlo? ¿Podría por favor proporcionar algunos escenarios de ejemplo?
Talespin_Kit

0

Las otras respuestas aquí estaban bien, pero eran insuficientes para mis necesidades. Necesitaba una solución que pudiera usar en mis scripts en cualquier máquina. Mi solución fue escribir un script de shell que pueda invocar desde los scripts donde lo necesito.

#!/bin/sh
if [ $# -eq 0 ] || [ $# -gt 2 ]; then
  printf 'Usage: respath path [working-directory]\n' >&2
  exit 1
fi
cantGoUp=

path=$1
if [ $# -gt 1 ]; then
  cd "$2"
fi
cwd=`pwd -P` #Use -P option to account for directories that are actually symlinks

#Handle non-relative paths, which don't need resolution
if echo "$path" | grep '^/' > /dev/null ; then
  printf '%s\n' "$path"
  exit 0
fi

#Resolve for each occurrence of ".." at the beginning of the given path.
#For performance, don't worry about ".." in the middle of the path.
while true
do
  case "$path" in
    ..*)
      if [ "$cwd" = '/' ]; then
        printf 'Invalid relative path\n' >&2
        exit 1
      fi
      if [ "$path" = '..' ]; then
        path=
      else
        path=`echo "$path" | sed 's;^\.\./;;'`
      fi
      cwd=`dirname $cwd`
      ;;
    *)
      break
      ;;
  esac
done

cwd=`echo "$cwd" | sed 's;/$;;'`
if [ -z "$path" ]; then
  if [ -z "$cwd" ]; then
    cwd='/'
  fi
  printf '%s\n' "$cwd"
else
  printf '%s/%s\n' "$cwd" "$path"
fi

Esta solución está escrita para Bourne Shell para la portabilidad. Tengo esto en un script llamado "respath.sh".

Este script se puede usar así:

respath.sh '/path/to/file'

O así

respath.sh '/relative/path/here' '/path/to/resolve/relative/to'

El script resuelve la ruta en el primer argumento utilizando la ruta del segundo argumento como punto de partida. Si solo se proporciona el primer argumento, el script resuelve la ruta relativa a su directorio de trabajo actual.


Tenga en cuenta que probablemente solo encontrará un shell Bourne en Solaris 10 y versiones anteriores hoy en día. Ese shell Bourne como la mayoría de las implementaciones de shell Bourne desde SVR2 (1984) tiene pwdincorporado y no es compatible -P(el shell Bourne no implementó ese manejo lógico de $ PWD como lo hacen los shells POSIX).
Stéphane Chazelas

Si deja de lado la compatibilidad de Bourne, puede usar la sintaxis POSIX $ {var ## pattern} y evitar esos ecos que se romperán con algunos valores.
Stéphane Chazelas

Olvidaste comprobar el estado de salida de cd (y pwd). Probablemente deberías usar cd -P --también en caso de que el primer argumento contenga algo ..
Stéphane Chazelas

Su casecheque debe ser en ..|../*)lugar de ..*.
Stéphane Chazelas

Hay un caso de falta de cotizacionesdirname $cwd
Stéphane Chazelas

0

En caso de que, además, tenga alguna ruta predefinida para $1(generalmente ${PWD}), lo siguiente funcionaría:

CWD="${1:-${PredefinedAbsolutePath}}"
if [ "${CWD}" != "${PredefinedAbsolutePath}}" ]; then
    case $1 in
        /*) echo "CWD=${CWD}"; ;;
        *) CWD=$(realpath $1); echo "CWD=${CWD}"; ;;
    esac
fi

0

Respetando la respuesta de todos los demás, encontré que la función a continuación es mucho más fácil y portátil entre Linux / MAC OSX que otras que encontré en todas partes. Podría ayudar a alguien.

#!/usr/bin/bash
get_absolute_path(){
    file_path=`pwd $1`
    echo "$file_path/$1"
}
#to assign to a variable
absolute_path=$(get_absolute_path "file.txt")
echo $absolute_path

-1

Suponga que la variable a almacena un nombre de ruta (a = "lo que sea")

1. Para la ruta potencial que contiene espacio:

c=$(grep -o " " <<< $a | wc -l); if (( $c > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi

2. Para la pregunta real, es decir, convertir la ruta a absoluta: readlink puede recuperar el contenido del enlace simbólico, que puede emplearse de la siguiente manera. (la nota readlink -fhabría sido perfecta, pero no está disponible al menos en Mac OS X bash, en el que -f significa FORMATOS ).

if [[ $(readlink $a) == "" ]]; then a=$(cd $a; pwd); else a=$(cd $(readlink $a); pwd); fi

3. Acabo de aprender pwd -Pen man pwd: -P es " Mostrar el directorio de trabajo físico actual (todos los enlaces simbólicos resueltos) " y por lo tanto

if (( $(grep -o " " <<< $a | wc -l) > "0" )); then a=$(sed 's/ /\\ /g' <<< $a); fi; a=$(cd $a; pwd -P)

funcionará también.

Conclusión: combine 1 con 2 para satisfacer sus dos requisitos, mientras que los nombres de ruta que contienen espacios ya se tienen en cuenta en los 3 más concisos .


Estás equivocado. Por ejemplo, si su camino incluye un espacio, la mayoría de los anteriores no funcionará.
Anthon

o un char de glob a veces. Y no resuelve enlaces simbólicos, como se solicitó.
dave_thompson_085

Eliminé mi respuesta de "comentario" sobre los nombres de ruta que contienen espacios y modifiqué la parte de "respuesta" en consecuencia.
vxtal
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.