【发布时间】:2013-02-07 09:20:26
【问题描述】:
我想将所有包含“特殊”一词的文件和目录重命名为“常规”。它应该保持区分大小写,这样“特殊”就不会变成“常规”。
如何在 bash 中递归执行此操作?
【问题讨论】:
我想将所有包含“特殊”一词的文件和目录重命名为“常规”。它应该保持区分大小写,这样“特殊”就不会变成“常规”。
如何在 bash 中递归执行此操作?
【问题讨论】:
尝试这样做(需要 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 是干什么用的?
**(代表递归)可能已经启用。
's/old/new/g'
使用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/' '{}' \+
【讨论】:
-exec command ; 中的find manpage。
find … -execdir … '{}' + 而不是… '{}' \;。添加了说明。
find /your/target/path/ -regex '.*special.*' -execdir rename 's/special/regular/' '{}' \+,否则会很慢!
recursively 的工作......
如果你不介意安装其他工具,那么你可以使用rnm:
rnm -rs '/special/regular/g' -dp -1 *
它将遍历所有目录/子目录(因为-dp -1),并将其名称中的 special 替换为 regular。
【讨论】:
对于那些只想重命名目录的人,你可以使用这个命令:
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.
【讨论】:
@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
这是另一种更便携的方法,并且不依赖于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
【讨论】:
对于rename 版本rename from util-linux 2.23.2,以下命令对我有用:
find . -type f -exec rename mariadb mariadb-proxy '{}' \;
【讨论】:
正如 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' '{}' \+;
【讨论】: