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
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
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:
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.# 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
verwendenBefehl 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).
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);
Schauen Sie sich 'realpath' an.
$ realpath
usage: realpath [-q] path [...]
$ realpath ../../../../../
/data/home
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
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);