Przekształcanie ścieżki względnej na ścieżkę bezwzględną bez dowiązania symbolicznego


63

Czy istnieje polecenie uniksowe, aby uzyskać ścieżkę absolutną (i kanonizowaną) ze ścieżki względnej, która może zawierać dowiązania symboliczne?

Odpowiedzi:


79

Możesz użyć readlinknarzędzia z -fopcją:

-f, --canonicalize

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

Niektóre dystrybucje, na przykład te, które używają GNU coreutils i FreeBSD , również zawierają realpath(1)narzędzie, które po prostu wywołuje realpath(3)i robi prawie to samo.


16
-fPrzełącznik nie istnieje w systemie Mac OS X (co najmniej od 10.8.5). Bez -fprzełącznika po prostu zwraca kod błędu.
iconoclast

3
Niektóre systemy nie mają ani readlinknor realpath- w szczególności Solaris i HP-UX.
Sildoreth

W przypadku problemu z komputerem Mac: brew install coreutils apple.stackexchange.com/a/69332/23040 , a jeśli nie chcesz wykonać kroku przekierowującego wszystkie standardowe narzędzia Mac CLI do nowo zainstalowanych odpowiedników GNU, po prostu zadzwoń greadlink.
Adrian

18

Przenośnie, PWDzmienna jest ustawiana przez powłokę na jedną bezwzględną lokalizację bieżącego katalogu. Każdy element tej ścieżki może być dowiązaniem symbolicznym.

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

Jeśli chcesz, aby wyeliminować .i ..jak dobrze, przejdź do katalogu zawierającego plik i uzyskać $PWDtam:

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

Nie ma przenośnego sposobu na śledzenie dowiązań symbolicznych. Jeśli masz ścieżkę do katalogu, w większości jednorożców $(cd -- "$dir" && pwd -P 2>/dev/null || pwd)zapewnia ścieżkę, która nie używa dowiązań symbolicznych, ponieważ powłoki, które śledzą dowiązania symboliczne, mają tendencję do implementowania pwd -P(„P” dla „fizycznego”).

Niektóre jednorożce zapewniają narzędzie do drukowania „fizycznej” ścieżki do pliku.

  • Stosunkowo najnowsze systemy Linux (z GNU coreutils lub BusyBox) mają readlink -f, podobnie jak FreeBSD ≥ 8.3, NetBSD ≥4,0 i OpenBSD już w wersji 2.2.
  • FreeBSD ≥4.3 ma realpath(jest także obecny na niektórych systemach Linux i jest w BusyBox).
  • Jeśli Perl jest dostępny, możesz użyć Cwdmodułu .

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

Dlaczego wprowadzasz coś do pwd( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd))? Wygląda na to, że nie obchodzi to standardowe wyjście.
Mateusz Piotrowski

1
@MateuszPiotrowski Typo, chciałem napisać||
Gilles

5

Czy pwdpasuje do twoich potrzeb? Podaje bezwzględną ścieżkę do bieżącego katalogu. A może to, czego chcesz, to realpath () .


3

alisteri rss67w tym artykule przedstawiam najbardziej stabilny, kompatybilny i najłatwiejszy sposób. Nigdy przedtem nie widziałem lepszego sposobu.

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

Jeśli chcesz wrócić do pierwotnej lokalizacji,

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

lub

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

Chciałbym, żeby to pomogło. To było dla mnie najlepsze rozwiązanie.


12
To nie jest tak dobry sposób. Zmiana katalogu i powrót do niego nie jest niezawodna: możesz nie mieć uprawnień do powrotu lub w międzyczasie nazwa katalogu mogła zostać zmieniona. Zamiast zmieniać katalogi w podpowłoce: ABSPATH=$(cd -- "$RELPATH" && pwd). Zwróć uwagę na podwójne cudzysłowy wokół podstawienia (aby nie łamać, jeśli ścieżka zawiera białe znaki i znaki globowania) oraz --(w przypadku, gdy ścieżka zaczyna się od -). Działa to również tylko w przypadku katalogów i nie kanonizuje dowiązań symbolicznych zgodnie z żądaniem. Zobacz moją odpowiedź, aby uzyskać więcej informacji.
Gilles

"> możesz nie mieć pozwolenia na powrót" Masz na myśli cd do katalogu, ale nie możesz wrócić? Czy możesz podać kilka przykładowych scenariuszy.
Talespin_Kit

0

Inne odpowiedzi tutaj były w porządku, ale były niewystarczające dla moich potrzeb. Potrzebowałem rozwiązania, którego mógłbym użyć w moich skryptach na dowolnym komputerze. Moim rozwiązaniem było napisanie skryptu powłoki, który można wywoływać ze skryptów tam, gdzie są potrzebne.

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

To rozwiązanie zostało napisane dla Bourne Shell pod kątem przenośności. Mam to w skrypcie o nazwie „respath.sh”.

Tego skryptu można użyć w następujący sposób:

respath.sh '/path/to/file'

Lub tak

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

Skrypt rozwiązuje ścieżkę w pierwszym argumencie, używając ścieżki z drugiego argumentu jako punktu początkowego. Jeśli podano tylko pierwszy argument, skrypt rozpoznaje ścieżkę względem bieżącego katalogu roboczego.


Zauważ, że prawdopodobnie obecnie znajdziesz tylko powłokę Bourne'a na Solarisie 10 i wcześniejszych. Ta powłoka Bourne'a jak większość implementacji powłoki Bourne'a od czasu SVR2 (1984) ma pwdwbudowaną i nie obsługuje -P(powłoka Bourne'a nie implementuje tej logicznej obsługi $ PWD jak powłoki POSIX).
Stéphane Chazelas

Jeśli porzucisz kompatybilność Bourne'a, możesz użyć składni POSIX $ {var ## pattern} i uniknąć echa, które zniszczy niektóre wartości.
Stéphane Chazelas

Zapomniałeś sprawdzić status wyjścia cd (i pwd). Prawdopodobnie powinieneś również użyć, cd -P --jeśli pierwszy argument zawiera trochę ..
Stéphane Chazelas

Twój caseczek powinien być ..|../*)zamiast ..*.
Stéphane Chazelas

Jest jeden przypadek brakujących cytatów wdirname $cwd
Stéphane Chazelas

0

W przypadku, gdy dodatkowo masz jakąś predefiniowaną ścieżkę $1(zwykle ${PWD}), działałyby:

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

0

Odnosząc się do odpowiedzi wszystkich innych, znalazłem poniższą funkcję, która jest bardzo łatwa i przenośna między Linuksem / MAC OSX niż inne, które znalazłem wszędzie. Może komuś pomóc.

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

Załóżmy, że zmienna a przechowuje nazwę ścieżki (a = „cokolwiek”)

1. W przypadku potencjalnej ścieżki zawierającej przestrzeń:

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

2. W przypadku rzeczywistego pytania, tj. Konwersji ścieżki na wartość bezwzględną: readlink może pobrać zawartość dowiązania symbolicznego, które można zastosować w następujący sposób. (uwaga readlink -fbyłaby idealna, ale nie jest dostępna przynajmniej w wersji bash dla Mac OS X, w której -f oznacza FORMATY ).

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

3. Właśnie się nauczyłem pwd -Pw man pwd: -P ma „ Wyświetlić fizyczny bieżący katalog roboczy (wszystkie dowiązania symboliczne rozwiązane) ” i tym samym

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

też będzie działać.

Wniosek: połącz 1 z 2, aby spełnić oba wymagania, a nazwy ścieżek zawierających spację zostały już omówione w bardziej zwięzłym 3 .


Mylisz się. Np. Jeśli twoja ścieżka zawiera spację, większość powyższych nie będzie działać.
Anthon

lub czasem glob char. I nie rozpoznaje dowiązań symbolicznych, zgodnie z żądaniem.
dave_thompson_085

Usunąłem swoją odpowiedź „komentarz” dotyczącą nazw ścieżek zawierających spacje i odpowiednio zmodyfikowałem część „odpowiedź”.
vxtal
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.