Konvertieren des relativen Pfads in einen absoluten Pfad ohne symbolische Verknüpfung

63

Gibt es einen Unix-Befehl, um den absoluten (und kanonisierten) Pfad von einem relativen Pfad abzurufen, der möglicherweise symbolische Links enthält?

Benjamin
quelle

Antworten:

79

Sie können das readlinkDienstprogramm mit der folgenden -fOption verwenden:

-f, --canonicalize

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

Einige Distributionen, zum Beispiel diejenigen, die GNU coreutils und FreeBSD verwenden , enthalten auch ein realpath(1)Hilfsprogramm, das im Grunde nur aufruft realpath(3)und so ziemlich dasselbe tut.

Matte
quelle
16
Der -fSwitch existiert nicht unter Mac OS X (mindestens ab 10.8.5). Ohne den -fSchalter wird nur ein Fehlercode zurückgegeben.
Iconoclast
3
Einige Systeme sind mit weder readlinknoch realpath- Solaris und HP-UX, insbesondere.
Sildoreth
Für das Mac-Problem: brew install coreutils apple.stackexchange.com/a/69332/23040 . Wenn Sie nicht den Schritt ausführen möchten, der alle Standard-Mac-CLI-Tools zu den neu installierten GNU-Entsprechungen umleitet, rufen Sie einfach an greadlink.
Adrian
18

Portabelerweise wird die PWDVariable von der Shell auf einen absoluten Ort des aktuellen Verzeichnisses gesetzt. Jede Komponente dieses Pfades kann eine symbolische Verknüpfung sein.

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

Wenn Sie beseitigen wollen .und ..auch in das Verzeichnis ändern , um die Datei enthält , und erhalten $PWDdort:

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

Es gibt keine tragbare Möglichkeit, symbolischen Links zu folgen. Wenn Sie einen Pfad zu einem Verzeichnis haben, stellen Sie auf den meisten Unices $(cd -- "$dir" && pwd -P 2>/dev/null || pwd)einen Pfad bereit, der keine symbolischen Verknüpfungen verwendet, da Shells, die symbolische Verknüpfungen verfolgen, in der Regel implementiert werden pwd -P("P" für "physisch").

Einige Unices bieten ein Dienstprogramm zum Drucken des „physischen“ Pfads zu einer Datei an.

  • Einigermaßen aktuelle Linux-Systeme (mit GNU-Coreutils oder BusyBox) haben readlink -febenso wie FreeBSD ≥8.3, NetBSD ≥4.0 und OpenBSD bereits 2.2.
  • FreeBSD ≥4.3 hat realpath(es ist auch auf einigen Linux-Systemen vorhanden, und es ist in BusyBox).
  • Wenn Perl verfügbar ist, können Sie das CwdModul verwenden .

    perl -MCwd -e 'print Cwd::realpath($ARGV[0])' path/to/file
Gilles 'SO - hör auf böse zu sein'
quelle
Warum leiten Sie etwas in pwd( $(cd -- "$dir" && pwd -P 2>/dev/null | pwd))? Es scheint sich nicht um Stdin zu kümmern.
Mateusz Piotrowski
1
@MateuszPiotrowski Tippfehler, ich wollte schreiben||
Gilles 'SO - hör auf, böse zu sein'
5

Ist pwdfit für Ihre Bedürfnisse? Es gibt den absoluten Pfad des aktuellen Verzeichnisses an. Oder vielleicht möchten Sie realpath () .

Xanpeng
quelle
3

alisterund rss67in diesem Artikel stellen wir den stabilsten, kompatibelsten und einfachsten Weg vor. Ich habe noch nie einen besseren Weg als diesen gesehen.

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

Wenn Sie zum ursprünglichen Speicherort zurückkehren möchten,

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

oder

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

Ich wünschte, das hilft. Dies war die beste Lösung für mich.

Eonil
quelle
12
Das ist eigentlich kein so guter Weg. Das Wechseln von einem Verzeichnis zu einem anderen ist nicht zuverlässig: Möglicherweise haben Sie nicht die Berechtigung, zurückzukehren, oder das Verzeichnis wurde in der Zwischenzeit umbenannt. Stattdessen ändern Verzeichnisse in einer Subshell: ABSPATH=$(cd -- "$RELPATH" && pwd). Beachten Sie die doppelten Anführungszeichen um die Ersetzung (um nicht zu brechen, wenn der Pfad Leerzeichen und glühende Zeichen enthält) und --(falls der Pfad mit beginnt -). Dies funktioniert auch nur für Verzeichnisse und kanonisiert symbolische Links nicht wie gewünscht. Siehe meine Antwort für weitere Details.
Gilles 'SO - hör auf böse zu sein'
"> Sie haben möglicherweise nicht die Erlaubnis, zurückzukehren" Sie meinen CD in ein Verzeichnis, können aber nicht zurückkehren? Könnten Sie bitte einige Beispielszenarien angeben?
Talespin_Kit
0

Die anderen Antworten hier waren in Ordnung, aber für meine Bedürfnisse nicht ausreichend. Ich brauchte eine Lösung, die ich in meinen Skripten auf jedem Computer verwenden konnte. Meine Lösung bestand darin, ein Shell-Skript zu schreiben, das ich von den Skripten aus aufrufen kann, wo ich es brauche.

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

Diese Lösung wurde für die Bourne-Shell entwickelt, um die Portabilität zu gewährleisten. Ich habe dies in einem Skript namens "respath.sh".

Dieses Skript kann folgendermaßen verwendet werden:

respath.sh '/path/to/file'

Oder so

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

Das Skript löst den Pfad im ersten Argument auf, wobei der Pfad aus dem zweiten Argument als Ausgangspunkt verwendet wird. Wenn nur das erste Argument angegeben wird, löst das Skript den Pfad relativ zu Ihrem aktuellen Arbeitsverzeichnis auf.

Sildoreth
quelle
Beachten Sie, dass Sie heutzutage wahrscheinlich nur unter Solaris 10 und früheren Versionen eine Bourne-Shell finden. Diese Bourne-Shell hat sich wie die meisten Bourne-Shell-Implementierungen seit SVR2 (1984) pwdeingebaut und wird nicht unterstützt -P(die Bourne-Shell hat diese logische $ PWD-Behandlung nicht implementiert, wie dies bei POSIX-Shells der Fall ist ).
Stéphane Chazelas
Wenn Sie die Bourne-Kompatibilität aufheben, können Sie die POSIX $ {var ## pattern} -Syntax verwenden und die Echos vermeiden, die bei einigen Werten zu Bruch gehen.
Stéphane Chazelas
Sie vergessen, den Exit-Status von cd (und pwd) zu überprüfen. Sie sollten wahrscheinlich auch verwenden, cd -P --wenn das 1. Argument einige enthält ..
Stéphane Chazelas
Ihr caseScheck sollte ..|../*)statt ..*.
Stéphane Chazelas
Es gibt einen Fall von fehlenden Zitaten indirname $cwd
Stéphane Chazelas
0

Falls Sie zusätzlich einen vordefinierten Pfad für $1(normalerweise ${PWD}) haben, würde Folgendes funktionieren:

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

Ich respektiere alle anderen Antworten und fand, dass die folgende Funktion zwischen Linux / MAC OSX sehr einfach und portabel ist als andere, die ich überall gefunden habe. Könnte jemandem helfen.

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

Angenommen, die Variable a speichert einen Pfadnamen (a = "whatever").

1. Für einen möglichen raumhaltigen Pfad:

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

2. Für die eigentliche Frage, dh Konvertieren des Pfads in Absolut: readlink kann Symlink-Inhalte abrufen, die wie folgt verwendet werden können. (Anmerkung readlink -fwäre perfekt gewesen, ist aber nicht in mindestens Mac OS X bash verfügbar, in dem -f für FORMATE steht .)

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

3. Soeben erlernt pwd -Pin man pwd: -P ist das " Anzeigen des physischen aktuellen Arbeitsverzeichnisses (alle symbolischen Verknüpfungen aufgelöst) " und damit

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

soll auch funktionieren.

Fazit: Kombinieren Sie 1 mit 2 , um beide Anforderungen zu erfüllen, während platzhaltende Pfadnamen in der übersichtlicheren Version 3 bereits berücksichtigt sind .

vxtal
quelle
Du liegst falsch. Wenn Ihr Pfad beispielsweise ein Leerzeichen enthält, funktionieren die meisten der oben genannten Punkte nicht.
Anthon
oder manchmal ein Glob Char. Und es werden keine Symlinks aufgelöst, wie angefordert wurde.
Dave_thompson_085
Ich habe meine Antwort "Kommentar" zu Pfadnamen mit Leerzeichen gelöscht und den Teil "Antwort" entsprechend geändert.
Vxtal