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?

Benzoes
źródło

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.

Mata
źródło
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
Gilles
źródło
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 () .

Xanpeng
źródło
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.

Eonil
źródło
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.

Sildoreth
źródło
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
Nikhil
źródło
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
lauksas
źródło
-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 .

vxtal
źródło
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