将相对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 

一些注意事项:

  1. 这也有解决所有符号链接的副作用。 这可能是也可能不是可取的,但通常是。
  2. 如果你引用一个不存在的目录, 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通常不会默认安装。 如果您不能确定realpathreadlink是否存在,您可以使用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);