Я не уверен, что эти пути дублируются. Учитывая относительный путь, как мне определить абсолютный путь с помощью сценария оболочки?
Пример:
relative path: /x/y/../../a/b/z/../c/d
absolute path: /a/b/c/d
Я не уверен, что эти пути дублируются. Учитывая относительный путь, как мне определить абсолютный путь с помощью сценария оболочки?
Пример:
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
foo; echo BAR
, не ведет себя так, как я ожидал). -1 чтобы привлечь ваше внимание ...
- person j_random_hacker; 03.02.2011
Cwd::abs_path
завершится ошибкой, если указанный путь не существует.
- person RJFalconer; 26.02.2013
cd "$1"; pwd
- это очень плохо, потому что если cd
завершится неудачей (если $1
не является допустимым каталогом), тогда pwd
предоставит текущий путь, а ABS_PATH
будет содержать сообщение об ошибке от cd
и текущий путь (да!). Более стабильный код _7 _ && `гарантирует, что pwd
будет выполняться тогда и только тогда, когда cd
успешно, иначе ABS_PATH
будет просто пустым.
- person LaurentValade; 11.09.2020
Самый надежный метод, с которым я столкнулся в unix, - это readlink -f
:
$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d
Пара предостережений:
readlink
даст пустой результат, если вы укажете несуществующий каталог. Если вы хотите поддерживать несуществующие пути, используйте вместо этого readlink -m
. К сожалению, этой опции нет в версиях readlink, выпущенных до ~ 2005 г.readlink -f
делает то же самое? В моей (OS X El Capitan) установке readlink -f
в первую очередь это stat -f
, и это показывает: -f Display information using the specified format. See the FORMATS section for a description of valid formats.
. Может ты установил coreutils
?
- person Kreisquadratur; 27.11.2015
# 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
Эта однострочная команда Perl использует Cwd::realpath
. Фактически существует три функции perl. Они принимают единственный аргумент и возвращают абсолютный путь. Подробности ниже взяты из документации Perl5> Core modules> Cwd.
abs_path()
использует тот же алгоритм, что и getcwd()
. Символические ссылки и компоненты относительного пути (.
и ..
) разрешены так, чтобы возвращать канонический путь, как и _ 21_.
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);
use Cwd qw(abs_path realpath fast_abs_path);
перед примерами? Как есть, все 3 примера приводят к неопределенным ошибкам подпрограммы.
- person arielf - Reinstate Monica; 06.08.2014
realpath
установки: alias realpath="perl -MCwd -e 'print Cwd::realpath ($ARGV[0]), qq<\n>'"
- person Steven Kramer; 25.09.2014
perl
в качестве замены realpath
. Я интегрировал вашу однострочную команду в ответ, чтобы она была полезна другим читателям SO. Ура ;-) (Я также проголосовал за некоторые из ваших ответов в качестве награды)
- person oHo; 26.09.2014
/etc/ARRAY(0x9afa68)
вместо /etc/file
, как я могу распечатать имя файла вместо дампа ARRAY?
- person Mark; 20.02.2015
$ARGV
в определении псевдонима, так что Perl sees Cwd::realpath ([0])
, который является ссылкой на массив. Escape $ARGV
в псевдониме. zsh не имеет этой проблемы.
- person Steven Kramer; 07.03.2015
Взгляните на «реальный путь».
$ realpath
usage: realpath [-q] path [...]
$ realpath ../../../../../
/data/home
Поскольку я сталкивался с этим много раз на протяжении многих лет, и на этот раз мне нужна была портативная версия на чистом bash, которую я мог бы использовать в OSX и Linux, я пошел дальше и написал одну:
Здесь живет живая версия:
https://github.com/keen99/shell-functions/tree/master/resolve_path
но ради ТАК, вот текущая версия (я считаю, что она хорошо протестирована ... но я открыт для отзывов!)
Может быть нетрудно заставить его работать для простой оболочки bourne (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
}
вот классический пример, благодаря пиву:
%% 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);
Я хотел использовать realpath
, но он недоступен в моей системе (macOS), поэтому я придумал этот сценарий:
#!/bin/sh
# NAME
# absolute_path.sh -- convert relative path into absolute path
#
# SYNOPSYS
# absolute_path.sh ../relative/path/to/file
echo "$(cd $(dirname $1); pwd)/$(basename $1)"
Пример:
./absolute_path.sh ../styles/academy-of-management-review.csl
/Users/doej/GitHub/styles/academy-of-management-review.csl
/
. Может быть, ищите ТАК канонический путь. - person Stephen P   schedule 28.10.2010