desenv-web-rp.com

Convertendo caminho relativo em caminho absoluto sem link simbólico

Existe um comando Unix para obter o caminho absoluto (e canônico) de um caminho relativo que pode conter links simbólicos?

66
Benjamin

Você pode usar o utilitário readlink , com a opção -f:

-f, --canonicalize

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

Algumas distribuições, por exemplo, aquelas que usam GNU coreutils e FreeBSD , também vêm com um utilitário realpath(1) que basicamente chama apenas realpath(3) e faz praticamente a mesma coisa.

83
Mat

Portably, o PWD variável é definido pelo Shell em um local absoluto do diretório atual. Qualquer componente desse caminho pode ser um link simbólico.

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

Se você deseja eliminar . E .., Mude para o diretório que contém o arquivo e obtenha $PWD Lá:

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

Não existe uma maneira portátil de seguir links simbólicos. Se você possui um caminho para um diretório, na maioria das unidades $(cd -- "$dir" && pwd -P 2>/dev/null || pwd) fornece um caminho que não usa links simbólicos, porque os shells que rastreiam links simbólicos tendem a implementar pwd -P ("P" para "fisica").

Alguns departamentos fornecem um utilitário para imprimir o caminho "físico" para um arquivo.

  • Sistemas Linux razoavelmente recentes (com GNU coreutils ou BusyBox) têm readlink -f , assim como FreeBSD ≥8.3, NetBSD ≥4.0 e OpenBSD já como 2.2.
  • O FreeBSD ≥4.3 possui realpath (também está presente em alguns sistemas Linux e no BusyBox).
  • Se o Perl estiver disponível, você poderá usar o Cwd module .

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

pwd é adequado para suas necessidades? Fornece o caminho absoluto do diretório atual. Ou talvez o que você queira seja realpath () .

5
xanpeng

alister e rss67 em este artigo introduza a maneira mais estável, compatível e mais fácil. Eu nunca vi uma maneira melhor do que isso antes.

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

Se você quiser voltar ao local original,

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

ou

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

Eu desejo que isso ajude. Esta foi a melhor solução para mim.

3
Eonil

Respeitando a resposta de todos, achei a função abaixo muito mais fácil e portátil entre linux/MAC OSX do que outras que encontrei em todos os lugares. Pode ajudar alguém.

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

As outras respostas aqui foram boas, mas foram insuficientes para minhas necessidades. Eu precisava de uma solução que pudesse usar nos meus scripts em qualquer máquina. Minha solução foi escrever um script do Shell que eu possa chamar dos scripts em que eu preciso.

#!/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 solução foi escrita para o Bourne Shell para portabilidade. Eu tenho isso em um script chamado "respath.sh".

Este script pode ser usado assim:

respath.sh '/path/to/file'

Ou assim

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

O script resolve o caminho no primeiro argumento usando o caminho do segundo argumento como ponto de partida. Se apenas o primeiro argumento for fornecido, o script resolverá o caminho relativo ao seu diretório de trabalho atual.

0
Sildoreth

Caso, além disso, você tenha algum caminho predefinido para $1 (usualmente ${PWD}), o seguinte funcionaria:

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