webentwicklung-frage-antwort-db.com.de

Relativer Pfad in absoluten Pfad konvertieren?

Ich bin nicht sicher, ob diese Pfade Duplikate sind. Wie ermittle ich unter Berücksichtigung des relativen Pfads den absoluten Pfad mithilfe eines Shell-Skripts?

Beispiel:

relative path: /x/y/../../a/b/z/../c/d

absolute path: /a/b/c/d
55
josh

Von diese Quelle kommt:

#!/bin/bash

# Assume parameter passed in is a relative path to a directory.
# For brevity, we won't do argument type or length checking.

ABS_PATH=`cd "$1"; pwd` # double quotes for paths that contain spaces etc...
echo "Absolute path: $ABS_PATH"

Sie können auch einen Perl-Einzeiler verwenden, z. mit Cwd::abs_path

48
DVK

Die zuverlässigste Methode, auf die ich in Unix gestoßen bin, ist readlink -f:

$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d

Ein paar Vorsichtsmaßnahmen:

  1. Dies hat auch den Nebeneffekt, dass alle Symlinks aufgelöst werden. Dies kann wünschenswert sein oder auch nicht, ist es aber normalerweise.
  2. readlink gibt ein leeres Ergebnis aus, wenn Sie auf ein nicht vorhandenes Verzeichnis verweisen. Wenn Sie nicht vorhandene Pfade unterstützen möchten, verwenden Sie readlink -m stattdessen. Leider gibt es diese Option nicht für Versionen von readlink, die vor ~ 2005 veröffentlicht wurden.
51
bukzor

Mit bash

# Directory
relative_dir="folder/subfolder/"
absolute_dir="$( cd "$relative_dir" && pwd )"

# File
relative_file="folder/subfolder/file"
absolute_file="$( cd "${relative_file%/*}" && pwd )"/"${relative_file##*/}"
  • ${relative_file%/*} Ist dasselbe Ergebnis wie dirname "$relative_file"
  • ${relative_file##*/} Ist dasselbe Ergebnis wie basename "$relative_file"

Vorsichtsmaßnahmen : Löst symbolische Links nicht auf (d. H. Kanonisiert Pfad nicht) => Unterscheidet möglicherweise nicht alle Duplikate, wenn Sie symbolische Links verwenden.


realpath verwenden

Befehl realpath erledigt den Job. Eine Alternative ist die Verwendung von readlink -e (Oder readlink -f). Jedoch wird realpath nicht oft standardmäßig installiert. Wenn Sie nicht sicher sind, ob realpath oder readlink vorhanden ist, können Sie es mit Perl ersetzen (siehe unten).


Mit Perl

Steven Kramer schlägt einen Shell-Alias ​​vor, wenn realpath in Ihrem System nicht verfügbar ist:

$ alias realpath="Perl -MCwd -e 'print Cwd::realpath(\$ARGV[0]),qq<\n>'"
$ realpath path/folder/file
/home/user/absolute/path/folder/file

oder wenn Sie lieber direkt mit Perl arbeiten:

$ Perl -MCwd -e 'print Cwd::realpath($ARGV[0]),qq<\n>' path/folder/file
/home/user/absolute/path/folder/file

Dieser einzeilige Perl-Befehl verwendet Cwd::realpath. Tatsächlich gibt es drei Perl-Funktionen. Sie nehmen ein einzelnes Argument und geben den absoluten Pfadnamen zurück. Die folgenden Details stammen aus der Dokumentation Perl5> Kernmodule> Cwd .

  • abs_path() verwendet denselben Algorithmus wie getcwd(). Symbolische Links und relative Pfadkomponenten (. Und ..) Werden aufgelöst, um den kanonischen Pfadnamen zurückzugeben, genau wie realpath .

    use Cwd 'abs_path';
    my $abs_path = abs_path($file);
    
  • realpath() ist ein Synonym für abs_path()

    use Cwd 'realpath';
    my $abs_path = realpath($file);
    
  • fast_abs_path() ist eine gefährlichere, aber möglicherweise schnellere Version von abs_path()

    use Cwd 'fast_abs_path';
    my $abs_path = fast_abs_path($file);
    

Diese Funktionen werden nur auf Anfrage exportiert. => Verwenden Sie daher Cwd, um den Fehler "Undefined subroutine" zu vermeiden, auf den arielf hingewiesen hat. Wenn Sie alle drei Funktionen importieren möchten, können Sie eine einzelne Zeile use Cwd Verwenden:

use Cwd qw(abs_path realpath fast_abs_path);
19
olibre

Schauen Sie sich 'realpath' an.

$ realpath

usage: realpath [-q] path [...]

$ realpath ../../../../../

/data/home
18
SteveMc

Da ich dies im Laufe der Jahre oft erlebt habe und diesmal eine reine Bash-Portable-Version brauchte, die ich unter OSX und Linux verwenden konnte, schrieb ich eine:

Die lebende Version lebt hier:

https://github.com/keen99/Shell-functions/tree/master/resolve_path

aber zum Wohle von SO, hier ist die aktuelle Version (Ich glaube, es ist gut getestet .. aber ich bin offen für Feedback!)

Es könnte nicht schwierig sein, es für einfache bourne Shell (sh) zum Laufen zu bringen, aber ich habe es nicht versucht ... Ich mag $ FUNCNAME zu sehr. :)

#!/bin/bash

resolve_path() {
    #I'm bash only, please!
    # usage:  resolve_path <a file or directory> 
    # follows symlinks and relative paths, returns a full real path
    #
    local owd="$PWD"
    #echo "$FUNCNAME for $1" >&2
    local opath="$1"
    local npath=""
    local obase=$(basename "$opath")
    local odir=$(dirname "$opath")
    if [[ -L "$opath" ]]
    then
    #it's a link.
    #file or directory, we want to cd into it's dir
        cd $odir
    #then extract where the link points.
        npath=$(readlink "$obase")
        #have to -L BEFORE we -f, because -f includes -L :(
        if [[ -L $npath ]]
         then
        #the link points to another symlink, so go follow that.
            resolve_path "$npath"
            #and finish out early, we're done.
            return $?
            #done
        Elif [[ -f $npath ]]
        #the link points to a file.
         then
            #get the dir for the new file
            nbase=$(basename $npath)
            npath=$(dirname $npath)
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        Elif [[ -d $npath ]]
         then
        #the link points to a directory.
            cd "$npath"
            ndir=$(pwd -P)
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition inside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            echo "npath [[ $npath ]]" >&2
            return 1
        fi
    else
        if ! [[ -e "$opath" ]]
         then
            echo "$FUNCNAME: $opath: No such file or directory" >&2
            return 1
            #and break early
        Elif [[ -d "$opath" ]]
         then 
            cd "$opath"
            ndir=$(pwd -P)
            retval=0
            #done
        Elif [[ -f "$opath" ]]
         then
            cd $odir
            ndir=$(pwd -P)
            nbase=$(basename "$opath")
            retval=0
            #done
        else
            echo "$FUNCNAME: ERROR: unknown condition outside link!!" >&2
            echo "opath [[ $opath ]]" >&2
            return 1
        fi
    fi
    #now assemble our output
    echo -n "$ndir"
    if [[ "x${nbase:=}" != "x" ]]
     then
        echo "/$nbase"
    else 
        echo
    fi
    #now return to where we were
    cd "$owd"
    return $retval
}

hier ist ein klassisches Beispiel, dank Brew:

%% ls -l `which mvn`
lrwxr-xr-x  1 draistrick  502  29 Dec 17 10:50 /usr/local/bin/[email protected] -> ../Cellar/maven/3.2.3/bin/mvn

wenn Sie diese Funktion verwenden, wird der Pfad -real- zurückgegeben:

%% cat test.sh
#!/bin/bash
. resolve_path.inc
echo
echo "relative symlinked path:"
which mvn
echo
echo "and the real path:"
resolve_path `which mvn`


%% test.sh

relative symlinked path:
/usr/local/bin/mvn

and the real path:
/usr/local/Cellar/maven/3.2.3/libexec/bin/mvn
1
keen

Vielleicht hilft das:

$path = "~user/dir/../file" 
$resolvedPath = glob($path); #   (To resolve paths with '~')
# Since glob does not resolve relative path, we use abs_path 
$absPath      = abs_path($path);
0
Rohan