我有一些文件和文件夹,它们全都是大写,我想将它们重命名为小写。在 Linux 系统的 bash 中执行此操作的最佳方法是什么?
举个例子,我可能有:
.
|-- FOLDER0
| |-- SUBFOLDERA
| `-- SUBFOLDERB
`-- FOLDER1
`-- AFILE.TXT
我想将其转换为:
.
|-- folder0
| |-- subfoldera
| `-- subfolderb
`-- folder1
`-- afile.txt
我可能可以编写一个深度优先递归脚本来执行此操作(深度优先确保文件和子文件夹在其父文件夹之前重命名),但我想知道是否有更好的方法。rename
可能有用,但它似乎不支持递归。
答案1
find . -depth -print0 | xargs -0 rename -n '$_ = lc $_'
一旦您确定它正在执行您想要的操作,请取出 -n 标志。
答案2
这更像是对这个论坛运作方式的评论和元观察,但我强烈认为应该更大声地表达出来,而不是在 rudedog 的回答中发表评论。这也是一条针对可能有问题的人的评论相似的回答 David Dean 的问题,但并不完全相同。
使用重命名文件的递归操作很容易造成大量破坏。我再说一遍,因为这非常重要。使用重命名文件的递归操作可以非常非常快地破坏大量数据。您可以快速使系统完全无法使用。您可以非常快速地删除 99% 的数据。应该采取此类行动非常仔细并经过深思熟虑、备份和测试运行。
我是非常对这个特定问题的答案持谨慎态度,因为它依赖于几个特定的默示假设:
- 我使用的“rename”版本与您使用的版本相同,并且它们都具有我习惯的安全功能。据我所知,“rename”不是 unix 中的标准、常规实用程序。它似乎是某些发行版中存在的一些巧妙脚本。
- 如上所述,“重命名”具有一些防止覆盖文件的安全功能。
- 要么被混合的文件具有明确的压缩大小写结果,要么如果生成的子目录中有一些大写文件也没什么大不了的,因为压缩大小写结果发生了冲突,并且如果目标名称已经存在,则名称更改机制不执行任何操作。
我完全可以接受走捷径。但我试着去理解,有些事情是一条捷径,以及这种捷径的局限性是什么,这样我知道什么时候需要运行始终正确的程序,或者快 10,000 倍但在某些边缘情况下失败的捷径。
简而言之——上述使用重命名的脚本在 90% 的情况下是 100% 合理的。在 100% 的情况下 100% 正确的解决方案实际上有点复杂,需要一些智慧来处理命名空间冲突。
但正如我之前所说,非常谨慎对待递归文件操作,尤其是当它们只处理权限或文件名等元数据时。它们速度很快,而且如果不备份就很难逆转……
以下是如何在 bash 或 ksh 或其他具有“typeset”的现代 shell 中编写“重命名”命令的示例。我们将此脚本命名为 /tmp/squash
#!/usr/local/bin/pdksh
# use some shell that supports typeset such as ksh, pdksh, or bash
# call this script from "xargs -0" and feed it with "find -print0"
typeset -l targetname || { echo "This shell doesn't support typeset!" >&2 ; exit 1 ; }
for file
do
count=""
target="$file"
targetpath="${target%/*}/"
targetname="${target##*/}"
if
[[ "$file" == "$targetpath$targetname" ]] || [[ "$file" == . ]]
then
:
else
while
test -e "$targetpath/$targetname""$count"
do
count=$((${count:-0}+1))
done
echo "renaming $file to $targetpath$targetname$count" >&2
mv -n "$file" "$targetpath$targetname$count"
fi
done
现在,您可以运行以下两个命令并将所有文件压缩,并且不会覆盖任何文件。
find /path/to/files -type f -print0 | xargs -0 /tmp/squash
find /path/to/files -type d -depth -print0 | xargs -0 /tmp/squash
并且我假设在运行程序时,相关目录中不会放入任何内容或重命名任何内容。
答案3
我将听从其他人的回答,但 -type f 和 -type d 作为 find 的参数将分别返回文件和目录。如果您想先更改文件,然后更改目录...那么请先更改文件,然后更改目录。