【问题标题】:Get grandparent directory in bash script - rename files for a directory in their paths在 bash 脚本中获取祖父目录 - 为路径中的目录重命名文件
【发布时间】:2014-02-11 18:49:50
【问题描述】:

我有以下脚本,当我得到一堆需要重命名为包含它们的目录名称的文件时,我通常会使用它。

现在的问题是我需要将文件重命名为上两级的目录。我怎样才能得到祖父母目录来完成这项工作?

使用以下内容,我会收到类似此示例的错误: “mv:无法将 ./48711/zoom/zoom.jpg 移动到 ./48711/zoom/./48711/zoom.jpg:没有这样的文件或目录”。这是在 CentOS 5.6 上运行的。

我希望最终文件命名为:48711.jpg

#!/bin/bash

function dirnametofilename() {
  for f in $*; do
    bn=$(basename "$f")
    ext="${bn##*.}"
    filepath=$(dirname "$f")
    dirname=$(basename "$filepath")
    mv "$f" "$filepath/$dirname.$ext"
  done
}

export -f dirnametofilename

find . -name "*.jpg" -exec bash -c 'dirnametofilename "{}"'  \;

find .

【问题讨论】:

  • 使用两个句点 (..) 向上一个目录,所以../../ 是祖父目录。

标签: linux bash path centos batch-rename


【解决方案1】:

另一种方法是使用

(cd ../../; pwd)

如果在任何顶级路径(例如//usr//usr/share/)中执行此操作,您将获得/ 的有效目录,但当您深入一层时,您将开始查看结果:/usr/share/man/ 将返回 /usr/my/super/deep/path/is/awesome/ 将返回 /my/super/deep/path,依此类推。

您也可以将其存储在变量中:

GRANDDADDY="$(cd ../../; pwd)"

然后将其用于脚本的其余部分。

【讨论】:

    【解决方案2】:

    假设文件路径不以/ 结尾,如果你使用dirname 则不应该这样,你可以这样做

    Parent = "${filepath%/*}"
    Grandparent = "${filepath%/*/*}"
    

    所以做这样的事情

    [[ "${filepath%/*/*}" == "" ]] && echo "Path isn't long enough" || echo "${filepath%/*/*}"
    

    如果您使用相对路径(如find .),这也可能不起作用。在这种情况下,您将需要使用

    filepath=$(dirname "$f")
    filepath=$(readlink -f "$filepath")
    

    而不是

    filepath=$(dirname "$f")
    

    此外,您永远不会剥离扩展名,因此没有理由从文件中获取它然后再次附加它。

    【讨论】:

      【解决方案3】:

      注意:
      * 此答案解决了 OP 的特定问题,在其上下文中,“祖父目录”是指:包含文件的目录的 目录(它是从 文件的 角度来看的祖父路径)。
      * 相比之下,鉴于问题的通用 title,此处的其他答案(仅)侧重于获取 目录的 祖父母目录; generic 问题的简洁答案是grandParentDir=$(cd ../..; printf %s "$PWD") 获取完整路径,grandParentDirName=$(cd ../..; basename -- "$PWD") 获取目录。名字而已。

      尝试以下方法:

      find . -name '*.jpg' \
        -execdir bash -c \
         'old="$1"; new="$(cd ..; basename -- "$PWD").${old##*.}"; echo mv "$old" "$new"' - {} \;
      

      注意:为了安全起见,echo 被添加到 mv 前面 - 删除它以执行实际重命名。

      • -execdir ..\; 在包含给定匹配文件的特定目录中执行指定命令,并将{} 扩展为每个文件的文件名。

      • bash -c 用于执行一个小的临时脚本:

        • $(cd ..; basename -- "$PWD") 确定包含文件的目录的目录名,即文件的祖父路径观点。

        • ${old##*.} 是一个 Bash parameter expansion,它返回输入文件名的后缀(扩展名)。

        • 注意{} - 手头的文件名 - 如何作为第二个 参数传递给命令以绑定到$1,因为bash -c 使用第一个设置$0(这里设置为虚拟值_)。

      • 请注意,每个文件只是重命名,即保留在其原始目录中

      警告

      • 每个具有匹配文件的目录应该只包含 1 个匹配文件,否则多个文件将按顺序重命名为相同的目标名称 - 实际上,只有最后一个重命名的文件将继续存在。

      【讨论】:

        【解决方案4】:

        你不能使用 realpath ../../readlink -f ../../ 吗?请参阅thisreadlink(1)realpath(3)canonicalize_file_name(3)realpath(1)。您可能想在 Debian 或 Ubuntu 上安装 realpath 软件包。可能 CentOS 有一个等效的软件包。 (readlink 应该始终可用,它在GNU coreutils 中)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-08-02
          • 2021-11-27
          • 2010-12-29
          • 2018-04-10
          • 1970-01-01
          • 2014-04-21
          • 1970-01-01
          • 2017-04-03
          相关资源
          最近更新 更多