【问题标题】:How do I get the absolute directory of a file in bash?如何在 bash 中获取文件的绝对目录?
【发布时间】:2013-07-10 17:27:18
【问题描述】:

我编写了一个 bash 脚本,该脚本将输入文件作为参数并读取它。
该文件包含一些路径(相对于其位置)到所使用的其他文件。

我希望脚本转到包含输入文件的文件夹,以执行更多命令。

那么,我如何从输入文件中获取文件夹(并且只是文件夹)?(在 linux 中。)

【问题讨论】:

  • 您是给出输入文件的完整路径还是仅给出相对于当前工作目录的路径?
  • dhm: 输入给出相对路径,我想要绝对路径 minus 文件名。

标签: linux bash shell


【解决方案1】:

要获取完整路径,请使用:

readlink -f relative/path/to/file

获取文件目录:

dirname relative/path/to/file

您也可以将两者结合起来:

dirname $(readlink -f relative/path/to/file)

如果您的系统上没有readlink -f,您可以使用这个*

function myreadlink() {
  (
  cd "$(dirname $1)"         # or  cd "${1%/*}"
  echo "$PWD/$(basename $1)" # or  echo "$PWD/${1##*/}"
  )
}

注意,如果你只需要移动到指定为相对路径的文件的目录,你不需要知道绝对路径,相对路径是完全合法的,所以只需使用:

cd $(dirname relative/path/to/file)

如果您希望(在脚本运行时)返回到原始路径,请使用pushd 而不是cd,完成后使用popd


* 虽然上面的myreadlink 在这个问题的上下文中已经足够好了,但它相对于上面建议的readlink 工具有一些限制。例如,它没有正确地跟随指向具有不同 basename 的文件的链接。

【讨论】:

  • 请注意,readlink -f 不能在 OS X 上运行,很遗憾。
  • 我不想要整个路径,我只想要文件夹。但这提供了足够的帮助:readlink -f relativeFileLocation | xargs 目录名
  • @EmilSit :你是对的——本机。但您可以brew install coreutils 获取。 stackoverflow.com/a/4031502/1022967.
  • 请不要推荐使用${1%/*}${1##*/} 作为dirnamebasename 的替代品。如果你给它一个简单的文件名,第一个中断(dirname foo.bar 正确地是.),第二个中断是一个以斜杠结尾的目录(basename /foo/bar/,正确地是bar)。
  • @ChenLevy 有些人可能倾向于使用它来提高速度(我认为basename/dirname 不是内置的),他们会看到它在首先,但似乎没有充分的理由在未来的某个时候突然中断。我会避免将其作为一种选择,或者否认它不是真正的防弹替代品。
【解决方案2】:

查看realpath,它在GNU/LinuxFreeBSDNetBSD 上可用,但在OpenBSD 6.8 上不可用。我使用类似的东西:

CONTAININGDIR=$(realpath ${FILEPATH%/*})

做你想做的事。

【讨论】:

  • realpath 对我来说很奇怪,它解析了相对目录的符号链接
  • 谢谢!在 Mac OS 上为我工作
【解决方案3】:
$cat abs.sh
#!/bin/bash
echo "$(cd "$(dirname "$1")"; pwd -P)"

一些解释:

  1. 此脚本获取相对路径作为参数"$1"
  2. 然后我们得到该路径的 dirname 部分(您可以将 dir 或文件传递给此脚本):dirname "$1"
  3. 然后我们cd "$(dirname "$1");进入这个相对目录
  4. pwd -P 并获取绝对路径。 -P 选项将避免符号链接
  5. 作为最后一步,我们echo

然后运行你的脚本:

abs.sh your_file.txt

【讨论】:

    【解决方案4】:

    这对文件和文件夹都有效:

    absPath(){
        if [[ -d "$1" ]]; then
            cd "$1"
            echo "$(pwd -P)"
        else 
            cd "$(dirname "$1")"
            echo "$(pwd -P)/$(basename "$1")"
        fi
    }
    

    【讨论】:

      【解决方案5】:

      在 GitHub 上试用我们的新 Bash 库产品 realpath-lib,我们已将其免费提供给社区并不受阻碍地使用。它干净、简单且有据可查,因此非常值得学习。你可以这样做:

      get_realpath <absolute|relative|symlink|local file path>
      

      这个函数是库的核心:

      if [[ -f "$1" ]]
      then
          # file *must* exist
          if cd "$(echo "${1%/*}")" &>/dev/null
          then
              # file *may* not be local
              # exception is ./file.ext
              # try 'cd .; cd -;' *works!*
              local tmppwd="$PWD"
              cd - &>/dev/null
          else
              # file *must* be local
              local tmppwd="$PWD"
          fi
      else
          # file *cannot* exist
          return 1 # failure
      fi
      
      # reassemble realpath
      echo "$tmppwd"/"${1##*/}"
      return 0 # success
      
      }
      

      它是 Bash 4+,不需要任何依赖,还提供 get_dirname、get_filename、get_stemname 和 validate_path。

      【讨论】:

        【解决方案6】:

        我一直在使用 readlink -f 在 linux 上工作

        所以

        FULL_PATH=$(readlink -f filename)
        DIR=$(dirname $FULL_PATH)
        
        PWD=$(pwd)
        
        cd $DIR
        
        #<do more work>
        
        cd $PWD
        

        【讨论】:

        • 不要在 Bash 中使用大写的变量名,它总有一天会与已经存在的变量发生冲突......哦,现在就是这一天:你知道变量 PWD 已经存在于 Bash 中吗它的值实际上是当前目录吗?并使用更多的引号。
        【解决方案7】:

        上述答案的问题在于使用“./”输入的文件,例如“./my-file.txt”

        解决方法(许多):

            myfile="./somefile.txt"
            FOLDER="$(dirname $(readlink -f "${ARG}"))"
            echo ${FOLDER}
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-04-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-07-22
          • 1970-01-01
          • 2012-04-06
          相关资源
          最近更新 更多