【问题标题】:How to extract directory path from file path?如何从文件路径中提取目录路径?
【发布时间】:2011-09-01 12:59:32
【问题描述】:

在 Bash 中,如果是 VAR="/home/me/mydir/file.c",我如何获得 "/home/me/mydir"

【问题讨论】:

标签: bash


【解决方案1】:

dirnamebasename 是您正在寻找的用于提取路径组件的工具:

$ VAR='/home/pax/file.c'
$ DIR="$(dirname "${VAR}")" ; FILE="$(basename "${VAR}")"
$ echo "[${DIR}] [${FILE}]"
[/home/pax] [file.c]

它们不是内部的 bash 命令,但它们是 POSIX 标准的一部分 - 请参阅 dirnamebasename。因此,它们可能在大多数能够运行bash 的平台上可用或可以获得。

【讨论】:

  • 为什么在变量名周围使用括号,而不是“$VAR”?
  • stackoverflow.com/questions/8748831/… 回答了上述问题。
  • @user658182 在这个特定的例子中,这是出于习惯,而不是必要。
  • export 是不必要的,echos are useless.
  • @tripleee:export 是我的习惯,只是为了确保将变量传递给子shell。 echo 语句用于展示如何将输出转换为变量,但我可能应该全力以赴(我现在拥有)。尽管这些都不会真正影响答案的“肉”,但我会进行调整。对于改进我的答案的建设性批评,我总是很感激。
【解决方案2】:
$ export VAR=/home/me/mydir/file.c
$ export DIR=${VAR%/*}
$ echo "${DIR}"
/home/me/mydir

$ echo "${VAR##*/}"
file.c

为了避免依赖basenamedirname

【讨论】:

  • 因为两者都是 POSIX 的一部分,所以依赖应该不是问题。
  • orkoden ,你是对的。我回答的目的是表明没有义务执行两个额外的过程。 bash 对于用例来说是自给自足的。
  • 我正在使用 Emmanuel 的方法,因为我希望传递文件或文件夹名称,然后计算文件夹路径。使用这个正则表达式是正确的,而 dirname 函数在我输入文件夹时返回父文件夹。
  • 但是,如果 $VAR 中没有路径信息,${VAR%/*}/test 会产生一个意外的值,等于 $VAR/test 而 $(dirname $VAR) 会产生更可预测的值和适当的 ./test 值。这很重要,因为前者会尝试将文件名视为目录,而后者则可以。
  • 这应该是公认的答案。 dirnamebasename 有它们的位置,但如果路径已经在 shell 变量中,使用 shell 的内置工具比调用外部进程更高效和优雅。
【解决方案3】:

在相关说明中,如果您只有文件名或相对路径,dirname 本身将无济于事。对我来说,答案最终是readlink

fname='txtfile'    
echo $(dirname "$fname")                # output: .
echo $(readlink -f "$fname")            # output: /home/me/work/txtfile

然后您可以将两者结合起来得到目录。

echo $(dirname $(readlink -f "$fname")) # output: /home/me/work

【讨论】:

  • 如果不存在多个路径组件,您应该使用readlink -m "$fname" 递归地规范化给定名称
【解决方案4】:

如果您关心目标文件是符号链接,首先您可以检查它并获取原始文件。下面的 if 子句可能会对您有所帮助。

if [ -h $file ]
then
 base=$(dirname $(readlink $file))
else
 base=$(dirname $file)
fi

【讨论】:

    【解决方案5】:
    HERE=$(cd $(dirname $BASH_SOURCE) && pwd)
    

    new_path=$(dirname ${BASH_SOURCE[0]}) 获取完整路径的位置。您使用cd new_path 更改当前目录,然后运行pwd 以获取当前目录的完整路径。

    【讨论】:

    • 太棒了,最多态的选项!
    • 这实际上似乎是对另一个问题的回答。 The quoting is broken.
    【解决方案6】:

    我正在玩这个并想出了一个替代方案。

    $ VAR=/home/me/mydir/file.c
    
    $ DIR=`echo $VAR |xargs dirname`
    
    $ echo $DIR
    /home/me/mydir
    

    我喜欢的部分是它很容易扩展备份树:

    $ DIR=`echo $VAR |xargs dirname |xargs dirname |xargs dirname`
    
    $ echo $DIR
    /home
    

    【讨论】:

      【解决方案7】:

      您可以使用How to find the last field using 'cut' 的方法尝试这样的事情:

      说明

      • rev/home/user/mydir/file_name.c 反转为 c.eman_elif/ridym/resu/emoh/
      • cut 使用/ 作为分隔符,并选择第二个字段,即ridym/resu/emoh/,删除字符串直到/ 第一次出现
      • 最后,我们再次反转得到/home/user/mydir
      $ VAR="/home/user/mydir/file_name.c"
      $ echo $VAR | rev | cut -d"/" -f2- | rev
      /home/user/mydir
      

      【讨论】:

      • 不建议将“/”(在文件名中无效)替换为空格(在文件名中有效)。如果您必须使用这样的解决方案,最好只删除所有内容,直到最后一个“/”字符,包括最后一个“/”字符。
      • @MartynDavis 请根据您的建议查看我的更新答案
      • 这不是 OP 要求的。
      • @m42 根据 OP 要求更新了我的答案。请查看其更新版本。
      • @alper;是的,现在这就是 OP 所要求的。 :)
      【解决方案8】:

      这是我用于递归修剪的脚本。当然,将 $1 替换为您想要的目录。

      BASEDIR=$1
      IFS=$'\n'
      cd "$BASEDIR"
       for f in $(find . -type f -name ' *')
       do 
          DIR=$(dirname "$f")
          DIR=${DIR:1}
          cd "$BASEDIR$DIR"
          rename 's/^ *//' *
       done
      

      【讨论】:

      • find 的输出上使用for 循环是一种反模式,也是许多错误的根源。这种构造本质上是有限的,如果find 产生的结果包含空格或其他shell 元字符,更不用说换行符了。
      猜你喜欢
      • 2012-10-04
      • 1970-01-01
      • 2015-04-26
      • 1970-01-01
      • 2010-10-01
      • 2011-02-01
      • 2013-06-08
      相关资源
      最近更新 更多