web-dev-qa-db-fra.com

Conversion d'un chemin relatif en chemin absolu sans lien symbolique

Existe-t-il une commande Unix pour obtenir le chemin absolu (et canonisé) à partir d'un chemin relatif qui peut contenir des liens symboliques?

66
Benjamin

Vous pouvez utiliser l'utilitaire readlink , avec l'option -f:

-f, --canonicalize

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

Certaines distributions, par exemple celles qui utilisent GNU coreutils et FreeBSD , sont également fournies avec un utilitaire realpath(1) qui appelle simplement realpath(3) et fait à peu près la même chose.

83
Mat

Portablement, la variable PWD est définie par le shell à un emplacement absolu du répertoire courant. Tout composant de ce chemin peut être un lien symbolique.

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

Si vous souhaitez également supprimer . Et .., Accédez au répertoire contenant le fichier et obtenez $PWD À cet endroit:

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

Il n'y a aucun moyen portable de suivre les liens symboliques. Si vous avez un chemin vers un répertoire, alors sur la plupart des unités, $(cd -- "$dir" && pwd -P 2>/dev/null || pwd) fournit un chemin qui n'utilise pas de liens symboliques, car les shells qui suivent les liens symboliques ont tendance à implémenter pwd -P ("P" pour "physique").

Certains unités fournissent un utilitaire pour imprimer le chemin "physique" vers un fichier.

  • Les systèmes Linux raisonnablement récents (avec GNU coreutils ou BusyBox) ont readlink -f , tout comme FreeBSD ≥8.3, NetBSD ≥4.0 et OpenBSD dans le passé) comme 2.2.
  • FreeBSD ≥4.3 a realpath (il est également présent sur certains systèmes Linux et se trouve dans BusyBox).
  • Si Perl est disponible, vous pouvez utiliser le module Cwd .

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

pwd est-il adapté à vos besoins? Il donne le chemin absolu du répertoire courant. Ou peut-être que vous voulez realpath () .

5
xanpeng

alister et rss67 in cet article présente la manière la plus stable, compatible et la plus simple. Je n'ai jamais vu de meilleure façon que celle-ci auparavant.

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

Si vous souhaitez revenir à l'emplacement d'origine,

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

ou

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

Je souhaite que cela aide. C'était la meilleure solution pour moi.

3
Eonil

En respectant la réponse de tout le monde, j'ai trouvé la fonction ci-dessous très facile et portable entre Linux/MAC OSX que d'autres que j'ai trouvées partout. Pourrait aider quelqu'un.

#!/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
0
lauksas

Les autres réponses ici étaient correctes mais insuffisantes pour mes besoins. J'avais besoin d'une solution que je pouvais utiliser dans mes scripts sur n'importe quelle machine. Ma solution a été d'écrire un script Shell que je peux invoquer depuis les scripts où j'en ai besoin.

#!/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

Cette solution est écrite pour le Bourne Shell pour la portabilité. J'ai ceci dans un script nommé "respath.sh".

Ce script peut être utilisé comme ceci:

respath.sh '/path/to/file'

Ou comme ça

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

Le script résout le chemin dans le premier argument en utilisant le chemin du deuxième argument comme point de départ. Si seul le premier argument est fourni, le script résout le chemin relatif à votre répertoire de travail actuel.

0
Sildoreth

Dans le cas, en outre, vous disposez d'un chemin prédéfini pour $1 (d'habitude ${PWD}), les éléments suivants fonctionneraient:

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