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.