63

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

我怎样才能在bash中递归地做到这一点?

4

8 回答 8

113

使用的解决方案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/' '{}' \+
于 2013-02-21T21:42:39.627 回答
88

尝试这样做(要求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命令的路径。


如果您没有此命令,请搜索您的包管理器进行安装或手动执行


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

于 2013-02-21T21:34:49.363 回答
7

如果您不介意安装另一个工具,那么您可以使用rnm

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

它将遍历所有目录/子目录(因为)并在其名称中用常规-dp -1替换特殊。

于 2016-05-07T09:33:53.033 回答
5

@speakr 的回答是我的线索。

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

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

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

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

将转变special-special.jpgregular-regular.jpg. 没有全局标志,你最终会得到regular-special.jpg.

仅供参考:默认情况下,Mac OSX 上未安装 GNU Rename。如果您使用的是Homebrew 包管理器brew install rename将对此进行补救。

于 2017-05-13T17:08:22.157 回答
3

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

文件:

查找 /path/ -type f -iregex '.*special.*' -execdir rename 's/special/regular/g' '{}' \+;

目录:

查找 /path/ -type d -iregex '.*special.*' -execdir rename 's/special/regular/g' '{}' \+;

文件和目录

查找 /path/ -iregex '.*special.*' -execdir rename 's/special/regular/g' '{}' \+;
于 2020-04-07T20:43:53.963 回答
3

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

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

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

它能做什么

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

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

例子

给出以下树:

├── 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
于 2018-12-11T23:54:40.083 回答
2

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

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

Note 类型现在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.
于 2017-02-11T04:31:15.033 回答
1

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

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

于 2019-12-03T15:09:37.800 回答