在 bash 脚本中获取祖父目录 - 为路径中的目录重命名文件

Posted

技术标签:

【中文标题】在 bash 脚本中获取祖父目录 - 为路径中的目录重命名文件【英文标题】:Get grandparent directory in bash script - rename files for a directory in their paths 【发布时间】: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 .

【问题讨论】:

使用两个句点 (..) 向上一个目录,所以../../ 是祖父目录。 【参考方案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 ../../ 吗?请参阅this、readlink(1)、realpath(3)、canonicalize_file_name(3) 和 realpath(1)。您可能想在 Debian 或 Ubuntu 上安装 realpath 软件包。可能 CentOS 有一个等效的软件包。 (readlink 应该始终可用,它在GNU coreutils 中)

【讨论】:

以上是关于在 bash 脚本中获取祖父目录 - 为路径中的目录重命名文件的主要内容,如果未能解决你的问题,请参考以下文章

如何从脚本本身中获取 Bash 脚本的源目录?

如何从脚本本身中获取 Bash 脚本的源目录?

如何将文件路径作为 bash 脚本中的参数传递给函数? [复制]

读取bash脚本中的输入,该脚本是路径中带有空格的目录[重复]

仅从 Bash 脚本中的路径获取文件名 [重复]

bash脚本获取绝对路径的最后一个目录名称