如何在Linux上将所有文件夹和文件重命名为小写?

243

我需要递归重命名一个完整的文件夹树,以便任何地方都没有大写字母出现(这是C++源代码,但不应该影响)。

如果忽略CVS和Subversion版本控制文件/文件夹将获得额外奖励。最好的方法是使用shell脚本,因为在任何Linux系统中都应该有可用的shell。

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

  1. 我认为相同小写名称的文件应该被覆盖;这是用户的问题。当在不区分大小写的文件系统上检出时,它也会将前一个文件覆盖为后一个文件。

  2. 我会考虑A-Z字符并将它们转换为a-z,其他所有内容只会引发问题(至少对于源代码而言)。

  3. 脚本需要在Linux系统上运行构建,因此我认为应省略对CVS或Subversion版本控制文件的更改。毕竟,这只是一个临时检出。也许"export"更合适。


先前发布的内容对于简单情况可以直接使用或稍作调整即可完美运行,但在批量重命名之前,有一些情况需要考虑:1. 如果在路径层次结构中存在两个或多个仅大小写不同的名称(例如ABCdefabcDEFaBcDeF),应该发生什么? 重命名脚本是否应该中止或只是警告并继续执行?2. 如何为非美国ASCII名称定义小写字母?如果可能存在这样的名称,是否应首先进行检查和排除操作?3. 如果您正在运行重命名操作 - Mihai Limbășan
31个回答

0
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/bar之前列出./foo),但仅适用于包含大写字符的文件。 -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命令输出替换后的文本。

正则表达式本身由两个捕获组成:直到最后一个 / 的部分(即文件的目录)和文件名本身。目录保持不变,但文件名转换为小写。因此,如果 find 输出 ./FOO/BAR,它将变成 mv -n -v -T ./FOO/BAR ./FOO/barmv-n 选项确保不会覆盖现有的小写文件。 -v 选项使 mv 输出它所做的每个更改(或未做的更改-如果 ./FOO/bar 已经存在,则输出类似于 ./FOO/BAR -> ./FOO/BAR,指出没有进行任何更改)。这里非常重要的是 -T - 它将目标文件视为目录。这将确保如果该目录存在,则不会将 ./FOO/BAR 移动到 ./FOO/bar 中。
find 结合使用,生成将执行的命令列表(方便验证实际执行之前的操作)。
sh

这个很容易理解。它将所有生成的 mv 命令路由到 shell 解释器。你可以用你喜欢的任何 shell 替换它,比如 bash

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接