将相对path转换为绝对path?
我不确定这些path是否重复。 鉴于相对path,如何使用shell脚本确定绝对path?
例:
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
一些注意事项:
- 这也有解决所有符号链接的副作用。 这可能是也可能不是可取的,但通常是。
- 如果你引用一个不存在的目录,
readlink
会给出一个空白的结果。 如果您要支持不存在的path,请改用readlink -m
。 不幸的是,这个选项在2005年以前发布的readlink版本中不存在。
看看“realpath”。
$ realpath usage: realpath [-q] path [...] $ realpath ../../../../../ /data/home
使用bash
# 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"
结果相同
警告 :不解决符号链接(即不canonicalizepath)=>如果您使用符号链接可能不区分所有重复。
使用realpath
Command realpath
执行这项工作。 另一种方法是使用readlink -e
(或readlink -f
)。 但是realpath
通常不会默认安装。 如果您不能确定realpath
或readlink
是否存在,您可以使用perlreplace它(请参见下文)。
使用Perl
如果您的系统中没有可用的实时realpath
Steven Kramer会提出一个shell别名:
$ 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函数。 他们采取一个单一的参数,并返回绝对path名。 以下详细信息来自文档Perl5>核心模块> Cwd 。
-
abs_path()
使用与getcwd()
相同的algorithm。 符号链接和相对path组件(.
和..
)被parsing为返回规范path名,就像实际path一样。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
来避免Cwd
指出的“Undefined subroutine”错误。 如果你想导入所有这三个函数,你可以使用一个use Cwd
行:
use Cwd qw(abs_path realpath fast_abs_path);
自从我经历了这么多年以来,这次我需要一个纯粹的bash便携版本,我可以在OSX和linux上使用,我继续写下了一个:
生活版本住在这里:
https://github.com/keen99/shell-functions/tree/master/resolve_path
但为了这个目的,这里是目前的版本(我觉得它已经很好的testing了..但我很乐意回应!)
可能不难,使它适用于朴素贝壳(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-path:
%% 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);