Convertendo caminho relativo para caminho absoluto sem link simbólico

57

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

    
por Benjamin 10.11.2011 / 07:01

7 respostas

71

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 vem com um utilitário realpath(1) que basicamente apenas chama realpath(3) e faz praticamente a mesma coisa.

    
por 10.11.2011 / 07:23
14

Por exemplo, a PWD variable é definida pelo shell como um valor absoluto localização 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ê quiser eliminar . e .. , mude para o diretório que contém o arquivo e obtenha $PWD there:

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

Não há maneira portátil de seguir links simbólicos. Se você tiver um caminho para um diretório, na maioria dos unices $(cd -- "$dir" && pwd -P 2>/dev/null || pwd) fornecerá um caminho que não usa links simbólicos, porque os shells que rastreiam links simbólicos tendem a implementar pwd -P (“P” para “físico”). / p>

Alguns unices 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 o FreeBSD ≥8.3, NetBSD ≥4.0 e OpenBSD desde 2.2.
  • O FreeBSD ≥4.3 tem realpath (também está presente em alguns Sistemas Linux, e é no BusyBox).
  • Se o Perl estiver disponível, você pode usar o % móduloCwd .

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

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

    
por 10.11.2011 / 07:21
3

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

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

Se você quiser voltar para o local original,

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

ou

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

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

    
por 13.12.2011 / 12:33
0

As outras respostas aqui foram boas, mas foram insuficientes para as minhas necessidades. Eu precisava de uma solução que pudesse usar em meus scripts em qualquer máquina. Minha solução foi escrever um script de shell que eu possa invocar dos scripts onde 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 o ponto inicial. Se apenas o primeiro argumento for fornecido, o script resolverá o caminho relativo ao seu diretório de trabalho atual.

    
por 19.05.2015 / 19:12
0

Além disso, se você tiver um caminho predefinido para $1 (geralmente ${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
    
por 21.09.2018 / 01:17
-1

Suponha que a variável a armazena um nome de caminho (a="whatever")

1. Para o caminho que contém espaço em potencial:

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

2. Para a pergunta real, ou seja, converter caminho para absoluto: readlink pode recuperar o conteúdo das ligações simbólicas, que podem ser empregadas da seguinte maneira. (note readlink -f teria sido perfeito, mas não está disponível no mínimo no bas do Mac OS X, em que -f significa FORMATOS .)

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

3. Apenas aprendemos pwd -P em man pwd : -P é para " Exibir o diretório de trabalho atual físico (todos os links simbólicos resolvidos) " e, portanto

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

funcionará também.

Conclusão: combine 1 com 2 para atender às suas necessidades, enquanto os nomes de caminho que contêm espaço já são atendidos no mais conciso 3 .

    
por 15.01.2017 / 08:56