ubuntu /bash 下递归重命名文件和目录

Posted

技术标签:

【中文标题】ubuntu /bash 下递归重命名文件和目录【英文标题】:Rename files and directories recursively under ubuntu /bash 【发布时间】:2013-02-07 09:20:26 【问题描述】:

我想将所有包含“特殊”一词的文件和目录重命名为“常规”。它应该保持区分大小写,这样“特殊”就不会变成“常规”。

如何在 bash 中递归执行此操作?

【问题讨论】:

Recursively rename files using find and sed的可能重复 【参考方案1】:

尝试这样做(需要 bash --version >= 4):

shopt -s globstar
rename -n 's/special/regular/' **

当您的测试正常时移除-n 开关

还有其他同名的工具可能会也可能不会做到这一点,所以要小心。

如果您运行以下命令 (GNU)

$ file "$(readlink -f "$(type -p rename)")"

你会得到类似

的结果
.../rename: Perl script, ASCII text executable

且不包含:

ELF

那么这似乎是正确的工具 =)

如果不是,则将其设为 Debian 和派生类 Ubuntu 的默认值(通常已经如此):

$ sudo update-alternatives --set rename /path/to/rename

(将/path/to/rename 替换为perl's rename 命令的路径。


如果你没有这个命令,搜索你的包管理器安装它或do it manually


最后但同样重要的是,这个工具最初是由 Perl 的父亲 Larry Wall 编写的。

【讨论】:

shopt -s globstar 是干什么用的? 它启用了 bash 功能**(代表递归)可能已经启用。 我的主目录中有大约 1700 个文件要重命名。这似乎太多了,这实际上是错误消息中的文本,太多的参数。 为了避免错误使用 for i in **;重命名 's///' "$i";在 globstar 之后完成 尝试重命名同名多次出现的模式的人应该在替换命令的末尾添加“g”标志:'s/old/new/g'【参考方案2】:

使用find的解决方案:

仅重命名文件

find /your/target/path/ -type f -exec rename 's/special/regular/' '' \;

仅重命名目录

find /your/target/path/ -type d -execdir rename 's/special/regular/' '' \+

要重命名文件和目录

find /your/target/path/ -execdir rename 's/special/regular/' '' \+

【讨论】:

@speakr,很好的解决方案,谢谢!您能否提供有关它正在做什么的更多详细信息,尤其是这部分“''\”?快速浏览并没有帮助,所以我认为这些信息对其他人也可能有用。 @DmitryGonchar 看看-exec command ; 中的find manpage。 @ThiloSchulz 可以,但您必须使用find … -execdir … '' + 而不是… '' \;。添加了说明。 如果文件很多,在find中利用正则表达式,对于上面的最后一个例子你使用:find /your/target/path/ -regex '.*special.*' -execdir rename 's/special/regular/' '' \+,否则会很慢! 太好了,谢谢。但是,在 OSX 上似乎没有完成 recursively 的工作......【参考方案3】:

如果你不介意安装其他工具,那么你可以使用rnm:

rnm -rs '/special/regular/g' -dp -1 *

它将遍历所有目录/子目录(因为-dp -1),并将其名称中的 special 替换为 regular

【讨论】:

这是从 Homebrew 安装的吗? @LokMac :我不认为它在 homebrew 中可用(我只为基于 debian 的操作系统打包二进制文件),如果你有 automake,你可以在任何 Unix 系统中安装它(说明在 @ 987654322@). 很棒的工具!为我工作!【参考方案4】:

对于那些只想重命名目录的人,你可以使用这个命令:

find /your/target/path/ -type d -execdir rename 's/special/regular/' '' \;

注释类型现在是d 用于目录,并使用-execdir

我还没有弄清楚如何一次性重命名文件和目录。

之前有人评论说,一旦它重命名了根文件夹,它就不能再遍历文件树了。有一个可用的-d 开关可以从下到上进行深度遍历,所以我相信根会最后重命名:

find -d /your/target/path/ -type d -execdir rename 's/special/regular/' '' \;

来自手册页 (man find):

 -d      Cause find to perform a depth-first traversal, i.e., directories are visited in post-order and all entries in a directory will be
         acted on before the directory itself.  By default, find visits directories in pre-order, i.e., before their contents.  Note, the
         default is not a breadth-first traversal.

【讨论】:

如果有人能澄清在一次通过中对文件和目录执行命令的操作,我将不胜感激,我将使用命令更新此答案。【参考方案5】:

@speakr's answer 是我的线索。

如果使用 -execdir 来转换文件和目录,您还需要从所示示例中删除 -type f。要拼写出来,请使用:

find /your/target/path/ -execdir rename 's/special/regular/' '' \+

此外,如果您想在给定的文件名中用regular 替换所有 出现的special,而不仅仅是第一次出现,请考虑将g(全局)标志添加到正则表达式。例如:

find /your/target/path/ -execdir rename 's/special/regular/g' '' \+

会将special-special.jpg 转换为regular-regular.jpg。如果没有全局标志,您最终会得到regular-special.jpg

仅供参考:默认情况下,Mac OSX 上未安装 GNU Rename。如果您使用的是Homebrew package manager,brew install rename 会解决这个问题。

【讨论】:

这个正确的句柄包括文件夹吗?例如/special/regular/regular-specilal.jpeg【参考方案6】:

这是另一种更便携的方法,并且依赖于rename 命令(因为它可能需要不同的参数,具体取决于发行版)。

它递归地重命名文件和目录:

find . -depth -name "*special*" | \
while IFS= read -r ent; do mv $ent $ent%special*regular$ent##*special; done

它的作用

使用带有-depth 参数的find 通过执行深度优先遍历来重新排序结果(即,目录中的所有条目都显示在目录本身之前)。 进行模式替换以仅修改路径中最后出现的 regular

这样首先修改文件,然后修改每个父目录。

示例

给出以下树:

├── aa-special-aa
│   └── bb-special
│       ├── special-cc
│       ├── special-dd
│       └── Special-ee
└── special-00

它以特定顺序生成那些mv 命令:

mv ./aa-special-aa/bb-special/special-cc ./aa-special-aa/bb-special/regular-cc
mv ./aa-special-aa/bb-special/special-dd ./aa-special-aa/bb-special/regular-dd
mv ./aa-special-aa/bb-special ./aa-special-aa/bb-regular
mv ./aa-special-aa ./aa-regular-aa
mv ./special-00 ./regular-00

获取以下树:

├── aa-regular-aa
│   └── bb-regular
│       ├── regular-cc
│       ├── regular-dd
│       └── Special-ee
└── regular-00

【讨论】:

非常感谢您的解释,完全符合我的需要。【参考方案7】:

对于rename 版本rename from util-linux 2.23.2,以下命令对我有用:

find . -type f -exec rename mariadb mariadb-proxy '' \;

【讨论】:

【参考方案8】:

正如 Rui Seixas Monteiro 所提到的,最好将 -iregex 模式选项与 Find 命令一起使用。我发现了以下作品,并在 U007D 提到的正则表达式中包含了全局标志:

文件:

find /path/ -type f -iregex '.*special.*' -execdir rename 's/special/regular/g' '' \+;

目录:

find /path/ -type d -iregex '.*special.*' -execdir rename 's/special/regular/g' '' \+;

文件和目录

find /path/ -iregex '.*special.*' -execdir rename 's/special/regular/g' '' \+;

【讨论】:

以上是关于ubuntu /bash 下递归重命名文件和目录的主要内容,如果未能解决你的问题,请参考以下文章

Bash 正则表达式重命名文件

使用 find 和 sed 递归地重命名文件

Bash 重命名扩展递归

如何在 MacOS 中递归地重命名文件夹和文件

查找文件,原地重命名 unix bash

如何在不使用重命名命令的情况下递归搜索目录并从文件名中删除开/关括号? [复制]