代码之家  ›  专栏  ›  技术社区  ›  josh

将相对路径转换为绝对路径?

  •  54
  • josh  · 技术社区  · 14 年前

    例子:

    relative path: /x/y/../../a/b/z/../c/d
    
    absolute path: /a/b/c/d
    
    6 回复  |  直到 11 年前
        1
  •  48
  •   trejder tvCa    10 年前

    this source

    #!/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

        2
  •  53
  •   bukzor    10 年前

    我在unix中遇到的最可靠的方法是 readlink -f :

    $ readlink -f /x/y/../../a/b/z/../c/d
    /a/b/c/d
    

    1. 这还具有解析所有符号链接的副作用。这可能是可取的,也可能不是可取的,但通常是可取的。
    2. readlink readlink -m 相反。不幸的是,此选项在~2005年之前发布的readlink版本中不存在。
        3
  •  19
  •   Toto    13 年前

    看看“realpath”。

    $ realpath
    
    usage: realpath [-q] path [...]
    
    $ realpath ../../../../../
    
    /data/home
    
        4
  •  19
  •   Community CDub    8 年前

    # 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 ). 然而 再分配 默认情况下不经常安装。如果你不能确定 再分配 readlink 现在,您可以使用perl替换它(见下文)。


    使用

    Steven Kramer 再分配 在您的系统中不可用:

    $ 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 Perl5 > Core modules > Cwd .

    • abs_path() 使用与 getcwd() . .. )决定返回规范路径名,就像 .

      use Cwd 'abs_path';
      my $abs_path = abs_path($file);
      
    • realpath() 绝对路径()

      use Cwd 'realpath';
      my $abs_path = realpath($file);
      
    • fast_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);
    
        5
  •  1
  •   keen    10 年前

    多年来,我遇到过很多次这种情况,这次我需要一个纯bash的可移植版本,可以在OSX和linux上使用,所以我继续写了一篇:

    活生生的版本住在这里:

    https://github.com/keen99/shell-functions/tree/master/resolve_path

    对于普通的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
    
        6
  •  0
  •   Rohan    13 年前

    这可能有助于:

    $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);