Преобразование относительного пути в абсолютный путь?
-
27-09-2019 - |
Вопрос
Я не уверен, что эти пути дубликаты. Учитывая относительный путь, как я могу определить абсолютный путь, используя сценарий оболочки?
Пример:
relative path: /x/y/../../a/b/z/../c/d
absolute path: /a/b/c/d
Решение
От Это источник Приходит:
#!/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"
Вы также можете сделать один-лайнер Perl, например, используя Cwd::abs_path
Другие советы
Самый надежный метод, который я сталкивался в Unix, readlink -f
:
$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d
Пара предупреждает:
- Это также имеет побочный эффект разрешения всех симLinks. Это может или не может быть желательно, но обычно есть.
readlink
даст пустое результат, если вы ссылаетесь на несуществующий каталог. Если вы хотите поддержать несуществующие пути, используйтеreadlink -m
вместо. К сожалению, эта опция не существует на версиях ReadLink, выпущенной до ~ 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%/*}
такой же результат, какdirname "$relative_file"
${relative_file##*/}
такой же результат, какbasename "$relative_file"
Оговорки: Не разрешает символические ссылки (т. Е. Не каницируют путь) => Не может различать все дубликаты, если вы используете символические ссылки.
С использованием realpath
Команда realpath
делает работу. Альтернатива - использовать readlink -e
(или readlink -f
). Однако realpath
не часто устанавливается по умолчанию. Если вы не можете быть уверены realpath
или readlink
Присутствует, вы можете заменить его, используя Perl (см. Ниже).
С использованием перл
Стивен Крамер Предлагает псевдоним оболочки, если realpath
не доступен в вашей системе:
$ alias realpath="perl -MCwd -e 'print Cwd::realpath(\$ARGV[0]),qq<\n>'"
$ realpath path/folder/file
/home/user/absolute/path/folder/file
Или если вы предпочитаете использовать напрямую Perl:
$ perl -MCwd -e 'print Cwd::realpath($ARGV[0]),qq<\n>' path/folder/file
/home/user/absolute/path/folder/file
Эта команда One-Line Perl использует Cwd::realpath
. Отказ Существуют на самом деле три функции Perl. Они берут один аргумент и вернут абсолютный путь. Ниже подробности из документации Perl5> Основные модули> CWD.
abs_path()
использует тот же алгоритм, что иgetcwd()
. Отказ Символические ссылки и компоненты относительного пути (.
а также..
) разрешены для возврата канонического пути, какrealpath
.use Cwd 'abs_path'; my $abs_path = abs_path($file);
realpath()
это синоним дляabs_path()
use Cwd 'realpath'; my $abs_path = realpath($file);
fast_abs_path()
является более опасным, но потенциально быстрее версияabs_path()
use Cwd 'fast_abs_path'; my $abs_path = fast_abs_path($file);
Эти функции экспортируются только по запросу => поэтому использовать Cwd
чтобы избежать «Неопределенный подпрограмм» Ошибка, как указано arielf.. Отказ Если вы хотите импортировать все эти три функции, вы можете использовать один use Cwd
линия:
use Cwd qw(abs_path realpath fast_abs_path);
Посмотрите на «RealPath».
$ realpath
usage: realpath [-q] path [...]
$ realpath ../../../../../
/data/home
Поскольку я пробежал в это много раз за эти годы, и на этот раз мне нужна была чистая портативная версия Bash, которую я мог бы использовать на OSX и Linux, я пошел вперед и написал один:
Живая версия живет здесь:
https://github.com/keen99/shell-function/tree/master/resolve_path.
Но ради этого, вот текущая версия (я чувствую, что это хорошо проверено .. Но я открыт для отзывы!)
Возможно, не может быть трудно сделать его работать на простых раковины Борна (SH), но я не пытался ... Мне очень нравится $ 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
}
Вот классический пример, спасибо 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
Используйте эту функцию, и это вернет -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
Может быть, это помогает:
$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);