用于递归重命名文件夹的 Bash 脚本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8065420/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash script to rename folders recursively
提问by user1037704
I want to rename all my folders and folders within these folders, so that all underscores in the folder name are replaced by spaces. Can you help me with that?
我想重命名我所有的文件夹和这些文件夹中的文件夹,以便文件夹名称中的所有下划线都替换为空格。你能帮我解决这个问题吗?
回答by Mark Longair
The answer that uses -execdiris simpler, but will only work with versions of findthat support -execdirsuch as GNU find, since POSIX only specifies -exec.
使用的答案-execdir更简单,但仅适用于find该支持的版本,-execdir例如 GNU find,因为POSIX 仅指定-exec.
If you just want to use bash, this is surprisingly tricky to get right, since you're renaming the directories that findis searching through. Even if you get the order right, by using the -depthoption to find, you need to make sure you only rewrite the last component of the path with each -exec. The following is a trivial variation of one of the examples given in the Bash FAQand seems to work OK for me:
如果您只想使用 bash,那么正确使用这会非常棘手,因为您正在重命名find正在搜索的目录。即使您的顺序正确,通过使用-depth选项find,您也需要确保只用每个-exec. 以下是Bash FAQ 中给出的示例之一的一个微不足道的变体,似乎对我来说工作正常:
find . -depth -name "*_*" -exec bash -c 'dir=${1%/*} base=${1##*/}; mv "" "$dir/${base//_/ }"' _ {} \;
That FAQ answer has more discussion about problem of recursively naming folders which may be of interest.
该常见问题解答对可能感兴趣的递归命名文件夹问题进行了更多讨论。
Update: Since that one-liner is rather complex, it might be worth breaking it down a little in the interests of explanation. Essentially, the findcommand is:
更新:由于该单行代码相当复杂,为了便于解释,可能值得将其分解一下。本质上,find命令是:
find . -depth -name "*_*" -exec bash -c [SOME-STUFF] _ {} \;
In other words, find all the directories which contain an underscore, and for each such directory, starting with the deepest, run the bash script [SOME-STUFF], with parameter 0 as _(to indicate that we don't care about it) and parameter 1 as the name of the file that find found. (findwill substitute the filename for {}after -exec. The \;just terminates the command that -execruns.)
换句话说,找到所有包含下划线的目录,对于每个这样的目录,从最深的开始,运行 bash 脚本[SOME-STUFF],参数 0 为_(表示我们不关心它)和参数 1 作为find 找到的文件的名称。(find将文件名替换为{}after -exec。\;只是终止-exec运行的命令。)
Then the [SOME-STUFF]part is made up of:
然后该[SOME-STUFF]部分由以下部分组成:
dir=${1%/*}
... which, using parameter expansion, will remove the shortest match for /*from the end of $1(the filename) and set dirto the result. Similarly, this part:
...使用参数扩展,将从(文件名)/*末尾删除最短匹配项$1并设置dir为结果。同样,这部分:
base=${1##*/}
... removes the longest match of */from the start of $1and sets baseto the result. So baseis just the last component of the path.
...*/从开头删除最长的匹配项$1并设置base为结果。所以,base仅仅是路径的最后一个组件。
Then the renaming is actually done by the mvcommand, which is:
然后重命名实际上是由mv命令完成的,即:
mv "" "$dir/${base//_/ }"
That again uses parameter expansion, this time with the ${parameter/pattern/string}syntax. The filename ($1) is renamed to $dirfollowed by $basebut with each underscore in $basereplaced with a space.
再次使用参数扩展,这次使用${parameter/pattern/string}语法。文件名 ( $1) 重命名为$dir后跟$base但每个下划线都$base替换为空格。
回答by Gilles Quenot
Yes, simply cd to /dir and :
是的,只需 cd 到 /dir 和:
find -depth -type d -execdir rename 's/_/ /g' {} \;
Depending of the distro, you need perl rename (sometimes prename).
根据发行版,您需要 perl 重命名(有时是 prename)。
If
如果
file $(type -p rename)
output contains ELF, that looks bad ;)
输出包含 ELF,看起来很糟糕;)
edit-depth and -execdir added
添加了编辑-depth 和 -execdir
回答by Gilles Quenot
If you have bash4, you can run :
如果你有 bash4,你可以运行:
for i in **; do [[ -d "$i" ]] || continue; mv "$i" "${i/_/ }"; done

