简体   繁体   English

Bash脚本以递归方式重命名文件夹

[英]Bash script to rename folders recursively

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? 你能帮帮我吗?

The answer that uses -execdir is simpler, but will only work with versions of find that support -execdir such as GNU find, since POSIX only specifies -exec . 使用-execdir的答案比较简单,但只适用于支持-execdirfind版本,例如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 find is searching through. 如果你只是想使用bash,那么要想做到这一点非常棘手,因为你正在重命名find的目录。 Even if you get the order right, by using the -depth option to find , you need to make sure you only rewrite the last component of the path with each -exec . 即使您通过使用-depth选项find正确的顺序,也需要确保只使用每个-exec重写路径的最后一个组件。 The following is a trivial variation of one of the examples given in the Bash FAQ and seems to work OK for me: 以下是Bash常见问题解答中给出一个示例的一个微不足道的变体,似乎对我有用:

find . -depth -name "*_*" -exec bash -c 'dir=${1%/*} base=${1##*/}; mv "$1" "$dir/${base//_/ }"' _ {} \;

That FAQ answer has more discussion about problem of recursively naming folders which may be of interest. 该FAQ答案有更多关于递归命名文件夹的问题的讨论,这可能是有意义的。


Update : Since that one-liner is rather complex, it might be worth breaking it down a little in the interests of explanation. 更新 :由于这种单线程相当复杂,为了解释起见,可能值得将其分解一点。 Essentially, the find command 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. 换句话说,找到包含下划线的所有目录,并且对于每个这样的目录,从最深处开始,运行bash脚本[SOME-STUFF] ,参数0为_ (表示我们不关心它)和参数1作为找到的文件的名称。 ( find will substitute the filename for {} after -exec . The \\; just terminates the command that -exec runs.) find会在-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 dir to the result. ...使用参数扩展 ,将从$1 (文件名)的末尾删除/*的最短匹配,并将dir设置为结果。 Similarly, this part: 同样,这部分:

base=${1##*/}

... removes the longest match of */ from the start of $1 and sets base to the result. ...从$1的开头删除*/的最长匹配,并将base设置为结果。 So base is just the last component of the path. 所以base只是路径的最后一个组成部分。

Then the renaming is actually done by the mv command, which is: 然后重命名实际上是由mv命令完成的,它是:

mv "$1" "$dir/${base//_/ }"

That again uses parameter expansion, this time with the ${parameter/pattern/string} syntax. 这再次使用参数扩展,这次使用${parameter/pattern/string}语法。 The filename ( $1 ) is renamed to $dir followed by $base but with each underscore in $base replaced with a space. 的文件名( $1 )被重命名为$dir随后$base但与每个强调在$base与空间置换。

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添加

如果你有bash4,你可以运行:

for i in **; do [[ -d "$i" ]] || continue; mv "$i" "${i/_/ }"; done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM