【问题标题】:Converting relative path into absolute path?将相对路径转换为绝对路径?
【发布时间】:2011-05-02 00:13:18
【问题描述】:

我不确定这些路径是否重复。给定相对路径,如何使用 shell 脚本确定绝对路径?

例子:

relative path: /x/y/../../a/b/z/../c/d

absolute path: /a/b/c/d

【问题讨论】:

标签: perl unix shell path absolute-path


【解决方案1】:

来自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

【讨论】:

  • 非常好。如果还给出了文件名怎么办。比如/x/y/../../a/b/z/../c/d.txt => /a/b/c/d.txt
  • 第一个在包含空格的路径上失败(尽管有趣的是,像 foo; echo BAR 这样的路径并没有像我预期的那样行为不端)。 -1 引起你的注意...
  • @j_random_hacker - (1) 已修复; (2) 用户收到新cmets的通知,无需通过投票来获得关注:)
  • +2 :) 我知道,“引起你的注意”是狡猾的词——“供应动机”更像是……我现在把它作为一般政策来做,因为我已经决定了不幸的是,结果好坏参半。
  • 有趣的是,如果指定的路径不存在,Cwd::abs_path 会失败。
【解决方案2】:

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

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

几个注意事项:

  1. 这也有解决所有符号链接的副作用。这可能是可取的,也可能不是可取的,但通常是这样的。
  2. 如果您引用不存在的目录,readlink 将给出空白结果。如果要支持不存在的路径,请改用readlink -m。不幸的是,这个选项在 ~2005 年之前发布的 readlink 版本中不存在。

【讨论】:

  • @jared-beck 你能证明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
  • 目前,OS X El Capitan 有一个不同的 readlink 命令,可以找到符号链接的真实路径,而不是将相对路径解析为绝对路径。因此,如果我们想要可移植,看起来我们只能更改目录然后返回。
【解决方案3】:

看看'realpath'。

$ realpath

usage: realpath [-q] path [...]

$ realpath ../../../../../

/data/home

【讨论】:

    【解决方案4】:

    这可能会有所帮助:

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

    【讨论】:

      【解决方案5】:

      使用

      # 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 默认情况下并不经常安装。如果您不能确定 realpathreadlink 是否存在,您可以使用 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 函数。它们采用单个参数并返回绝对路径名。以下详细信息来自文档Perl5 > Core modules > 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);
      

      【讨论】:

      • +1,但您能否通过在示例前添加 use Cwd qw(abs_path realpath fast_abs_path); 来使其更完整?照原样,所有 3 个示例都会产生“未定义的子例程”错误。
      • 具有不错的 Perl 但没有安装 realpath 的发行版的单行版本:alias realpath="perl -MCwd -e 'print Cwd::realpath ($ARGV[0]), qq&lt;\n&gt;'"
      • @olibre MacOSX,Perl v5.18.2。脚本地址:gist.github.com/thefosk/43296cb8bf74497c9d69
      • @Mark 你的shell 在别名的定义中扩展$ARGV,所以Perl sees Cwd::realpath ([0]),这是一个数组引用。在别名中转义 $ARGV。 zsh没有这个问题。
      • 查看我的编辑,它转义了别名,应该适用于 bash/zsh/ksh。
      【解决方案6】:

      由于这些年来我遇到过很多次,而这一次我需要一个可以在 OSX 和 linux 上使用的纯 bash 便携版本,所以我继续写了一个:

      活版在这里:

      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
      

      使用这个函数,它会返回-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
      

      【讨论】:

        【解决方案7】:

        我想使用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
        

        【讨论】:

          猜你喜欢
          • 2017-08-01
          • 2011-11-07
          • 2016-12-14
          • 1970-01-01
          相关资源
          最近更新 更多