【问题标题】:How to extract the name of immediate directory along with the filename?如何提取直接目录的名称以及文件名?
【发布时间】:2012-10-13 20:53:34
【问题描述】:

我有一个完整路径如下的文件

/a/b/c/d/filename.txt

如果我对它执行basename,我会得到filename.txt。但是这个文件名不是太独特。

所以,如果我可以将文件名提取为d_filename.txt 即更好。

{immediate directory}_{basename result}

我怎样才能达到这个结果?

【问题讨论】:

  • 如果您想对许多文件执行此操作,您需要提供更多信息。比如脚本应该在哪个目录中运行?另外,创建新文件名后,您想如何处理它?将其分配给 var?重命名原始文件?
  • 我在root 目录中。是的,我想将它分配给我程序中的一个变量。问题是补丁甚至可能是/a/b/c/anotherfile.txt,即文件在第四层级内的问题并不固定。
  • 代码已更新以反映这一点。请在此处查看我的答案 --> stackoverflow.com/questions/2340052/…

标签: unix sed awk


【解决方案1】:
file="/path/to/filename"
echo $(basename $(dirname "$file")_$(basename "$file"))

file="/path/to/filename"
filename="${file##*/}"
dirname="${file%/*}"
dirname="${dirname##*/}"
filename="${dirname}_${filename}"

【讨论】:

  • 我在文件夹层次结构中有很多不同的文件,所以我事先不知道文件夹的名称。
  • @eSKay:偶然发现了这个老问题,但想指出这个答案并不取决于事先知道名字;只需将任一解决方案中的 /path/to/filename 更改为文件的路径,然后逐字使用其余部分 - 它会起作用。
【解决方案2】:

此代码将从您运行脚本的目录开始递归地搜索您的层次结构。我已经对循环进行了编码,以便它可以处理您扔给它的任何文件名;带有空格、换行符等的文件名。

*注意**:循环当前被写入包含此脚本所在目录中的任何文件,它只查看它下面的子目录。这样做是因为这是确保脚本不将其自身包含在其处理中的最简单方法。如果由于某种原因您必须包含脚本所在的目录,则可以对其进行更改以适应此情况。

代码

#!/bin/bash

while IFS= read -r -d $'\0' file; do
    dirpath="${file%/*}"
    filename="${file##*/}"
    temp="${dirpath}_${filename}"
    parent_file="${temp##*/}"

    printf "dir: %10s  orig: %10s  new: %10s\n" "$dirpath" "$filename" "$parent_file"
done < <(find . -mindepth 2 -type f -print0)

测试树

$ tree -a
.
|-- a
|   |-- b
|   |   |-- bar
|   |   `-- c
|   |       |-- baz
|   |       `-- d
|   |           `-- blah
|   `-- foo
`-- parent_file.sh

输出

$ ./parent_file.sh
dir:  ./a/b/c/d  orig:       blah  new:     d_blah
dir:    ./a/b/c  orig:        baz  new:      c_baz
dir:      ./a/b  orig:        bar  new:      b_bar
dir:        ./a  orig:        foo  new:      a_foo

【讨论】:

  • 这并不总是有效。 /a/1/b/c/d/baz 和 /a/2/b/c/d/baz 将产生重复的名称“d_baz”。
  • 这是真的,但我想说你的评论比我自己更适合 OP,因为我的代码符合规定的要求。
【解决方案3】:
$ FILE=/a/b/c/d/f.txt
$ echo $FILE
/a/b/c/d/f.txt
$ echo $(basename ${FILE%%$(basename $FILE)})_$(basename $FILE)
d_f.txt

【讨论】:

    【解决方案4】:

    不需要调用外部命令

    s="/a/b/c/d/filename.txt"
    t=${s%/*}
    t=${t##*/}
    filename=${t}_${s##*/}
    

    【讨论】:

      【解决方案5】:

      举个例子:

       /a/1/b/c/d/file.txt
       /a/2/b/c/d/file.txt
      

      限定file.txt 并避免冲突的唯一可靠方法是将整个路径构建到新文件名中,例如

       /a/1/b/c/d/file.txt -> a_1_b_c_d_file.txt
       /a/2/b/c/d/file.txt -> a_2_b_c_d_file.txt
      

      如果您确定开头的部分内容对所有文件都是通用的,例如,如果您知道所有文件都位于上述目录 /a 下的某个位置,则您可以跳过开头的部分内容:

       /a/1/b/c/d/file.txt -> 1_b_c_d_file.txt
       /a/2/b/c/d/file.txt -> 2_b_c_d_file.txt
      

      要在每个文件的基础上实现这一点:

      # file="/path/to/filename.txt"
      new_file="`echo \"$file\" | sed -e 's:^/::' -e 's:/:_:g'`"
      # new_file -> path_to_filename.txt
      

      假设您想在目录及其子目录中递归执行此操作:

      # dir = /a/b
      ( cd "$dir" && find . | sed -e 's:^\./::' | while read file ; do
        new_file="`echo \"$file\" | sed -e 's:/:_:g'`"
        echo "rename $dir/$file to $new_file"
      done )
      

      输出:

      rename /a/b/file.txt to file.txt
      rename /a/b/c/file.txt to c_file.txt
      rename /a/b/c/e/file.txt to c_e_file.txt
      rename /a/b/d/e/file.txt to d_e_file.txt
      ...
      

      以上是高度可移植的,基本上可以在sh的任何变体下的任何Unix系统上运行(包括bashksh等)

      【讨论】:

        猜你喜欢
        • 2019-06-20
        • 2020-05-30
        • 1970-01-01
        • 2013-07-23
        • 1970-01-01
        • 1970-01-01
        • 2017-01-21
        • 1970-01-01
        • 2018-12-07
        相关资源
        最近更新 更多