Je ne sais pas si ces chemins sont des doublons. Compte tenu du chemin relatif, comment puis-je déterminer le chemin absolu à l'aide d'un script Shell?
Exemple:
relative path: /x/y/../../a/b/z/../c/d
absolute path: /a/b/c/d
De cette source vient:
#!/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"
Vous pouvez également faire une doublure Perl, par exemple en utilisant Cwd::abs_path
La méthode la plus fiable que j'ai rencontrée sous Unix est readlink -f
:
$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d
Quelques mises en garde:
readlink
donnera un résultat vide si vous référencez un répertoire inexistant. Si vous souhaitez prendre en charge des chemins inexistants, utilisez readlink -m
au lieu. Malheureusement, cette option n'existe pas sur les versions de readlink publiées avant ~ 2005.# 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%/*}
Est le même résultat que dirname "$relative_file"
${relative_file##*/}
Est le même résultat que basename "$relative_file"
Mises en garde : Ne résout pas les liens symboliques (c'est-à-dire ne canonise pas le chemin) => Peut ne pas différencier tous les doublons si vous utilisez des liens symboliques.
realpath
La commande realpath
fait le travail. Une alternative consiste à utiliser readlink -e
(Ou readlink -f
). Cependant, realpath
n'est pas souvent installé par défaut. Si vous ne pouvez pas être sûr que realpath
ou readlink
est présent, vous pouvez le remplacer en utilisant Perl (voir ci-dessous).
Steven Kramer propose un alias Shell si realpath
n'est pas disponible dans votre système:
$ alias realpath="Perl -MCwd -e 'print Cwd::realpath(\$ARGV[0]),qq<\n>'"
$ realpath path/folder/file
/home/user/absolute/path/folder/file
ou si vous préférez utiliser directement Perl:
$ Perl -MCwd -e 'print Cwd::realpath($ARGV[0]),qq<\n>' path/folder/file
/home/user/absolute/path/folder/file
Cette commande Perl sur une ligne utilise Cwd::realpath
. Il existe en fait trois fonctions Perl. Ils prennent un seul argument et renvoient le chemin absolu. Les détails ci-dessous proviennent de la documentation Perl5> Core modules> Cwd .
abs_path()
utilise le même algorithme que getcwd()
. Les liens symboliques et les composants de chemin relatif (.
Et ..
) Sont résolus pour renvoyer le nom de chemin canonique, tout comme realpath
.
use Cwd 'abs_path';
my $abs_path = abs_path($file);
realpath()
est un synonyme de abs_path()
use Cwd 'realpath';
my $abs_path = realpath($file);
fast_abs_path()
est une version plus dangereuse mais potentiellement plus rapide de abs_path()
use Cwd 'fast_abs_path';
my $abs_path = fast_abs_path($file);
Ces fonctions sont exportées uniquement sur demande => utilisez donc Cwd
pour éviter l'erreur "Sous-programme non défini" comme indiqué par arielf . Si vous souhaitez importer ces trois fonctions, vous pouvez utiliser une seule ligne use Cwd
:
use Cwd qw(abs_path realpath fast_abs_path);
Jetez un œil à "realpath".
$ realpath
usage: realpath [-q] path [...]
$ realpath ../../../../../
/data/home
Depuis que je l'ai rencontré plusieurs fois au fil des ans, et cette fois-ci, j'avais besoin d'une version portable bash pure que je pouvais utiliser sur OSX et linux, j'ai continué et j'en ai écrit une:
La version vivante vit ici:
https://github.com/keen99/Shell-functions/tree/master/resolve_path
mais pour le bien de SO, voici la version actuelle (je pense qu'elle est bien testée .. mais je suis ouvert aux commentaires!)
Cela pourrait ne pas être difficile de le faire fonctionner pour Shell Bourne ordinaire (sh), mais je n'ai pas essayé ... J'aime trop $ FUNCNAME. :)
#!/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
}
voici un exemple classique, grâce à brew:
%% ls -l `which mvn`
lrwxr-xr-x 1 draistrick 502 29 Dec 17 10:50 /usr/local/bin/mvn@ -> ../Cellar/maven/3.2.3/bin/mvn
utilisez cette fonction et elle renverra le chemin -real-:
%% 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
Peut-être que cela aide:
$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);