用于递归重命名文件夹的 Bash 脚本
Posted
技术标签:
【中文标题】用于递归重命名文件夹的 Bash 脚本【英文标题】:Bash script to rename folders recursively 【发布时间】:2011-12-25 07:27:30 【问题描述】:我想重命名我的所有文件夹和这些文件夹中的文件夹,以便文件夹名称中的所有下划线都替换为空格。你能帮我解决这个问题吗?
【问题讨论】:
【参考方案1】:是的,只需 cd 到 /dir 和 :
find -depth -type d -execdir rename 's/_/ /g' \;
根据发行版的不同,您需要 perl 重命名(有时是前缀)。
如果
file $(type -p rename)
输出包含 ELF,看起来很糟糕 ;)
编辑 -depth 和 -execdir 添加了
【讨论】:
这不起作用,因为在find
输出 'foo_bar/baz_quux' 之前将找到并重命名 'foo_bar' - 尝试重命名时将找不到后者。
没什么大不了的,可以加-depth
切换查找。
恐怕它仍然不起作用 - 在该示例中要调用的第一个命令是 rename 's/_/ /' ./foo_bar/bar_baz
,它会给出错误 Can't rename ./foo_bar/bar_baz ./foo bar/bar_baz: No such file or directory
- 如果您使用的是 rename
你需要一个正则表达式,它只会替换路径最后一个组件中的下划线。
尝试使用-execdir
而不是-exec
。
另一个错误是这只会替换目录名称中的第一个下划线 - 请尝试s/_/ /g
。【参考方案2】:
使用-execdir
的答案更简单,但仅适用于支持-execdir
的find
版本,例如GNU find,因为POSIX only specifies -exec
。
如果您只想使用 bash,那么要正确执行此操作非常棘手,因为您正在重命名 find
正在搜索的目录。即使你得到了正确的顺序,通过使用find
的-depth
选项,你需要确保只用每个-exec
重写路径的最后一个组件。以下是one of the examples given in the Bash FAQ 的一个简单变体,对我来说似乎没问题:
find . -depth -name "*_*" -exec bash -c 'dir=$1%/* base=$1##*/; mv "$1" "$dir/$base//_/ "' _ \;
该常见问题解答对递归命名文件夹的问题进行了更多讨论,这可能会引起人们的兴趣。
更新:由于那条线相当复杂,为了便于解释,可能值得将其分解一下。本质上,find
命令是:
find . -depth -name "*_*" -exec bash -c [SOME-STUFF] _ \;
也就是说,找到所有包含下划线的目录,对于每个这样的目录,从最深的开始,运行bash脚本[SOME-STUFF]
,参数0为_
(表示我们不关心它)和参数 1 作为找到的文件的名称。 (find
将在-exec
之后用文件名替换。
\;
只是终止-exec
运行的命令。)
那么[SOME-STUFF]
部分是由:
dir=$1%/*
... 使用parameter expansion,将从$1
(文件名)的末尾删除/*
的最短匹配,并将dir
设置为结果。同样,这部分:
base=$1##*/
... 从$1
的开头删除*/
的最长匹配并将base
设置为结果。所以base
只是路径的最后一个组成部分。
那么重命名实际上是通过mv
命令完成的,即:
mv "$1" "$dir/$base//_/ "
这再次使用参数扩展,这次使用$parameter/pattern/string
语法。文件名 ($1
) 重命名为 $dir
,后跟 $base
,但 $base
中的每个下划线都替换为空格。
【讨论】:
如果您希望替换值(在本例中为空格)是源自调用脚本的变量怎么办?在前。我已经包含 $SOMEVAR 不起作用。找 。 -depth -name "_" -exec bash -c 'dir=$1%/* base=$1##*/; mv "$1" "$dir/$base//_/$SOMEVAR"' _ \;【参考方案3】:如果你有 bash4,你可以运行:
for i in **; do [[ -d "$i" ]] || continue; mv "$i" "$i/_/ "; done
【讨论】:
以上是关于用于递归重命名文件夹的 Bash 脚本的主要内容,如果未能解决你的问题,请参考以下文章