我必须递归地重命名一个完整的文件夹树,这样就不会出现大写字母(这是c++源代码,但这无关紧要)。

忽略CVS和Subversion版本控制文件/文件夹的加分项。首选的方法是shell脚本,因为shell应该在任何Linux机器上可用。

关于文件重命名的细节有一些有效的争论。

I think files with the same lowercase names should be overwritten; it's the user's problem. When checked out on a case-ignoring file system, it would overwrite the first one with the latter, too. I would consider A-Z characters and transform them to a-z, everything else is just calling for problems (at least with source code). The script would be needed to run a build on a Linux system, so I think changes to CVS or Subversion version control files should be omitted. After all, it's just a scratch checkout. Maybe an "export" is more appropriate.


当前回答

find . -depth -name '*[A-Z]*'|sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'|sh

我没有尝试过这里提到的更详细的脚本,但是在我的Synology NAS上,没有一个命令行版本适合我。rename是不可用的,并且find的许多变体失败,因为它似乎坚持已经重命名的路径的旧名称(例如,如果它找到。/FOO后面跟着。/FOO/BAR,重命名。/FOO到。/FOO仍然会继续列出。/FOO/BAR,即使该路径不再有效)。以上命令对我来说没有任何问题。

下面是该命令每个部分的解释:


find . -depth -name '*[A-Z]*'

这将找到当前目录中的任何文件(更改。到您想要处理的任何目录),使用深度优先搜索(例如。,它会在./foo之前列出./foo/bar),但只针对包含大写字符的文件。name筛选器只应用于基本文件名,而不应用于完整路径。这里会列出。/FOO/BAR而不是。/FOO/BAR。这是可以的,因为我们不想重命名。/FOO/bar。虽然我们想重命名./FOO,但后面会列出这个(这就是-depth很重要的原因)。

这个命令本身对于首先查找要重命名的文件特别有用。在完全重命名命令之后使用此命令可以搜索由于文件名冲突或错误而仍然没有被替换的文件。


sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'

该部分读取find命令输出的文件,并使用正则表达式在mv命令中格式化它们。-n选项停止sed打印输入,搜索和替换正则表达式中的p命令输出替换后的文本。

The regex itself consists of two captures: the part up until the last / (which is the directory of the file), and the filename itself. The directory is left intact, but the filename is transformed to lowercase. So, if find outputs ./FOO/BAR, it will become mv -n -v -T ./FOO/BAR ./FOO/bar. The -n option of mv makes sure existing lowercase files are not overwritten. The -v option makes mv output every change that it makes (or doesn't make - if ./FOO/bar already exists, it outputs something like ./FOO/BAR -> ./FOO/BAR, noting that no change has been made). The -T is very important here - it treats the target file as a directory. This will make sure that ./FOO/BAR isn't moved into ./FOO/bar if that directory happens to exist.

使用此命令和find命令一起生成将执行的命令列表(可以方便地验证将执行什么而无需实际执行)


sh

这是不言自明的。它将所有生成的mv命令路由到shell解释器。您可以将其替换为bash或任何您喜欢的shell。

其他回答

我在Mac OS X上发现的最简单的方法是使用http://plasmasturm.org/code/rename/:上的重命名包

brew install rename
rename --force --lower-case --nows *

——force即使目标文件名已经存在,也要重命名。 ——lower-case将文件名全部转换为小写。 替换文件名中所有空格序列为单个下划线字符。

如果你使用Arch Linux,你可以从AUR安装rename)包,它提供了renamexm命令作为/usr/bin/renamexm可执行文件和一个手册页面。

它是一个非常强大的工具,可以快速重命名文件和目录。

转换为小写字母

rename -l Developers.mp3 # or --lowcase

转换为大写

rename -u developers.mp3 # or --upcase, long option

其他选项

-R --recursive # directory and its children

-t --test # Dry run, output but don't rename

-o --owner # Change file owner as well to user specified

-v --verbose # Output what file is renamed and its new name

-s/str/str2 # Substitute string on pattern

--yes # Confirm all actions

如果需要,您可以从这里获取示例Developers.mp3文件;)

最初的问题要求忽略SVN和CVS目录,这可以通过在find命令中添加-prune来实现。例如忽略CVS:

find . -name CVS -prune -o -exec mv '{}' `echo {} | tr '[A-Z]' '[a-z]'` \; -print

[编辑]我尝试了一下,在find中嵌入小写翻译并没有起作用,原因我实际上不明白。因此,将其修改为:

$> cat > tolower
#!/bin/bash
mv $1 `echo $1 | tr '[:upper:]' '[:lower:]'`
^D
$> chmod u+x tolower 
$> find . -name CVS -prune -o -exec tolower '{}'  \;

Ian

上面的大多数答案都很危险,因为它们不处理包含奇数字符的名称。对于这种情况,最安全的方法是使用find的-print0选项,该选项将以ASCII NUL而不是\n终止文件名。

下面是一个脚本,它只改变文件而不改变目录名,以免混淆find:

find .  -type f -print0 | xargs -0n 1 bash -c \
's=$(dirname "$0")/$(basename "$0");
d=$(dirname "$0")/$(basename "$0"|tr "[A-Z]" "[a-z]"); mv -f "$s" "$d"'

我对它进行了测试,它适用于包含空格、各种引号等的文件名。这很重要,因为如果您以根用户身份运行树中的其他脚本,其中包括由

touch \;\ echo\ hacker::0:0:hacker:\$\'\057\'root:\$\'\057\'bin\$\'\057\'bash

... 你猜怎么着……

更小的,我很喜欢:

rename 'y/A-Z/a-z/' *

在不区分大小写的文件系统上,比如OS X的HFS+,你会想要添加-f标志:

rename -f 'y/A-Z/a-z/' *