示例:
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
在Unix中,我遇到的最可靠的方法是readlink -f
:
$ readlink -f /x/y/../../a/b/z/../c/d
/a/b/c/d
几点注意事项:
readlink
如果引用不存在的目录,则会得到空结果。如果你想要支持不存在的路径,请使用 readlink -m
。不幸的是,这个选项在 ~2005 年之前发布的 readlink 版本中不存在。readlink -f
命令不可用。 - Lrireadlink -f
是否有同样的功能吗?在我的(OS X El Capitan)安装中,readlink -f
首先基本上就是stat -f
,并显示:-f
使用指定格式显示信息。请参阅FORMATS部分以获取有效格式的描述。也许你安装了coreutils
? - Kreisquadratur以下内容来自这个源:
#!/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 是为了引起你的注意... - j_random_hackerCwd::abs_path
函数将失败。 - RJFalconer# 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进行替代(参见下文)。
Steven Kramer提出了一个shell别名,如果您的系统中没有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 > 核心模块 > 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
的发行版,可以使用以下一行命令:alias realpath="perl -MCwd -e 'print Cwd::realpath ($ARGV[0]), qq<\n>'"
。该命令会为realpath
创建一个别名,并调用Perl的Cwd
模块来获取路径信息。 - Steven Kramerperl
作为 realpath
替代方案的想法。我已将您的一行命令整合到答案中,以便其他 Stack Overflow 的读者也能受益。祝好!(我还给了您一些赞作为奖励) - oHo$ARGV
,因此Perl看到了Cwd::realpath([0])
,它是一个数组引用。在别名中转义$ARGV
。zsh没有这个问题。 - Steven Kramer看一下 'realpath'。
$ realpath
usage: realpath [-q] path [...]
$ realpath ../../../../../
/data/home
由于多年来我遇到了这个问题很多次,而这一次我需要一个纯Bash便携版本,可以在OSX和Linux上使用,所以我决定自己写一个:
最新版本在此处获取:
https://github.com/keen99/shell-functions/tree/master/resolve_path
但为了SO的缘故,这是当前版本(我觉得它经过了充分的测试...但我乐意听取反馈!)
也许将其适用于普通的Bourne Shell(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
%% 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
我想使用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
也许这可以帮助:
$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);