How to rename all folders and files to lowercase on Linux?
我必须递归地重命名一个完整的文件夹树,这样就不会有大写字母出现在任何地方(它是C++源代码,但这不重要)。忽略cvs和svn控制文件/文件夹的奖励积分。首选的方法是shell脚本,因为shell应该在任何Linux设备上都可用。
有一些关于文件重命名详细信息的有效参数。
我认为具有相同小写名称的文件应该被覆盖,这是用户的问题。当在一个案例中签出时,忽略文件系统也会用后者覆盖第一个案例。
我会考虑a-z字符并将其转换为a-z,其他一切都只是为了解决问题(至少是源代码)。
在Linux系统上运行构建需要这个脚本,所以我认为应该忽略对cvs或svn控制文件的更改。毕竟,这只是一个临时结账。也许"出口"更合适。
我还是很喜欢小一点的
1 | rename 'y/A-Z/a-z/' * |
在不区分大小写的文件系统(如OS X的HFS+)上,您需要添加-f标志
1 | rename -f 'y/A-Z/a-z/' * |
使用
1 | find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \; |
这样可以避免在文件之前重命名目录,并尝试将文件移动到不存在的目录(例如,
或者,不使用
1 2 3 4 5 6 7 8 | for SRC in `find my_root_dir -depth` do DST=`dirname"${SRC}"`/`basename"${SRC}" | tr '[A-Z]' '[a-z]'` if ["${SRC}" !="${DST}" ] then [ ! -e"${DST}" ] && mv -T"${SRC}""${DST}" || echo"${SRC} was not renamed" fi done |
P.S.
后者允许更灵活地使用移动命令(如
1 | for f in `find`; do mv -v"$f""`echo $f | tr '[A-Z]' '[a-z]'`"; done |
如果你不需要关心效率的话,只需简单地尝试跟随。
1 2 | zip -r foo.zip foo/* unzip -LL foo.zip |
上面的大多数答案都是危险的,因为它们不处理包含奇数字符的名称。对于这种情况,最安全的选择是使用find的-print0选项,它将使用ascii nul而不是终止文件名。在这里,我提交这个脚本,它只更改文件,而不更改目录名,以免混淆find。
1 2 3 | 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"' |
我测试过它,它与包含空格、各种引号等的文件名一起工作。这很重要,因为如果您以根目录运行树上的其他脚本之一,其中包括由以下对象创建的文件:
1 | touch \;\ echo\ hacker::0:0:hacker:\$\'\057\'root:\$\'\057\'bin\$\'\057\'bash |
…好吧,猜猜看……
如果您已经有或设置了RENAME命令(例如,通过在Mac中安装BREW),则可以使用此命令:
1 | rename --lower-case --force somedir/* |
伙计,你们喜欢把事情搞得过于复杂……
重命名"y/a-z/a-z/"*
这适用于CentOS/RedHat或其他发行版,不使用
1 | for i in $( ls | grep [A-Z] ); do mv -i"$i""`echo $i | tr 'A-Z' 'a-z'`"; done |
来源:https://linuxconfig.org/rename-all-files-from-uppercase-to-lowercase-characters
(在某些发行版中,默认的
使用Larry Wall的文件名修复程序
1 2 3 4 5 6 7 8 | $op = shift or die $help; chomp(@ARGV = <STDIN>) unless @ARGV; for (@ARGV) { $was = $_; eval $op; die $@ if $@; rename($was,$_) unless $was eq $_; } |
这很简单
1 | find | fix 'tr/A-Z/a-z/' |
(fix当然是上面的脚本)
原始问题要求忽略svn和cvs目录,这可以通过向find命令添加-prune来完成。例如,忽略cvs:
1 | find . -name CVS -prune -o -exec mv '{}' `echo {} | tr '[A-Z]' '[a-z]'` \; -print |
[编辑]我尝试了这个方法,但由于我不太明白的原因,在搜索结果中嵌入小写翻译不起作用。因此,将此修改为:
1 2 3 4 5 6 | $> cat > tolower #!/bin/bash mv $1 `echo $1 | tr '[:upper:]' '[:lower:]'` ^D $> chmod u+x tolower $> find . -name CVS -prune -o -exec tolower '{}' \; |
伊恩
下面是我的次优解决方案,使用bash shell脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/bin/bash # first, rename all folders for f in `find . -depth ! -name CVS -type d`; do g=`dirname"$f"`/`basename"$f" | tr '[A-Z]' '[a-z]'` if ["xxx$f" !="xxx$g" ]; then echo"Renaming folder $f" mv -f"$f""$g" fi done # now, rename all files for f in `find . ! -type d`; do g=`dirname"$f"`/`basename"$f" | tr '[A-Z]' '[a-z]'` if ["xxx$f" !="xxx$g" ]; then echo"Renaming file $f" mv -f"$f""$g" fi done |
编辑:我根据目前的建议做了一些修改。现在文件夹都被正确重命名了,当权限不匹配时,mv不会询问问题,也不会重命名cvs文件夹(很遗憾,该文件夹中的cvs控制文件仍然被重命名)。
编辑:因为"find-depth"和"find sort-r"都以可用的顺序返回文件夹列表进行重命名,所以我更喜欢使用"-depth"搜索文件夹。
这是一个小的shell脚本,执行您的请求:
1 2 3 4 5 6 7 | root_directory="${1?-please specify parent directory}" do_it () { awk '{ lc= tolower($0); if (lc != $0) print"mv "" $0"" "" lc""" }' | sh } # first the folders find"$root_directory" -depth -type d | do_it find"$root_directory" ! -type d | do_it |
注意第一个查找中的深度操作。
使用MACOS,
安装
1 | brew install rename |
使用,
1 | find . -iname"*.py" -type f | xargs -I% rename -c -f "%" |
此命令查找扩展名为
1 | `f` - forces a rename |
例如,
1 2 3 4 5 6 7 | $ find . -iname"*.py" -type f ./sample/Sample_File.py ./sample_file.py $ find . -iname"*.py" -type f | xargs -I% rename -c -f "%" $ find . -iname"*.py" -type f ./sample/sample_file.py ./sample_file.py |
以前发布的将完全不受限制地工作,或者对简单情况进行一些调整,但是在运行批重命名之前,您可能需要考虑一些情况:
如果在路径层次结构中有两个或多个相同级别的名称(仅因情况而不同),如
如何定义非US-ASCII名称的小写?如果可能存在这样的名称,应该首先执行一次检查和排除传递吗?
如果在cvs或svn工作副本上运行重命名操作,则如果更改文件名或目录名的大小写,可能会损坏工作副本。脚本是否还应查找和调整内部管理文件,如.svn/entries或cvs/entries?
不可移植,仅限zsh,但相当简洁。
首先,确保加载了
1 | autoload -U zmv |
另外,确保
1 | setopt extendedglob |
然后使用:
1 | zmv '(**/)(*)~CVS~**/CVS' '${1}${(L)2}' |
以递归方式小写文件和目录,其中名称不是cvs。
在OSX中,mv-f显示"相同文件"错误,所以我重命名了两次。
1 | for i in `find . -name"*" -type f |grep -e"[A-Z]"`; do j=`echo $i | tr '[A-Z]' '[a-z]' | sed s/\-1$//`; mv $i $i-1; mv $i-1 $j; done |
1 | for f in `find -depth`; do mv ${f} ${f,,} ; done |
在这种情况下,我会使用python,以避免乐观地假设没有空格或斜线的路径。我还发现,与
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #!/usr/bin/env python2 import sys, os def rename_dir(directory): print('DEBUG: rename('+directory+')') # rename current directory if needed os.rename(directory, directory.lower()) directory = directory.lower() # rename children for fn in os.listdir(directory): path = os.path.join(directory, fn) os.rename(path, path.lower()) path = path.lower() # rename children within, if this child is a directory if os.path.isdir(path): rename_dir(path) # run program, using the first argument passed to this python script as the name of the folder rename_dir(sys.argv[1]) |
1 2 3 4 | ( find YOURDIR -type d | sort -r; find yourdir -type f ) | grep -v /CVS | grep -v /SVN | while read f; do mv -v $f `echo $f | tr '[A-Z]' '[a-z]'`; done |
首先从下到上重命名目录sort-r(其中-depth不可用),然后重命名文件。然后grep-v/cvs而不是find…-修剪,因为它更简单。对于大目录,对于中的f…会溢出一些外壳缓冲区。使用查找…|同时阅读以避免这种情况。
是的,这将删除不同的文件,只有在案件…
slugify重命名(regex)
不完全是OP要求的,但我希望在这一页上找到:
用于重命名文件的"slugify"版本,因此它们与URL类似(即仅包括字母数字、点和破折号):
1 | rename"s/[^a-zA-Z0-9\.]+/-/g" filename |
1 | find . -depth -name '*[A-Z]*'|sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'|sh |
我没有尝试过这里提到的更复杂的脚本,但是在我的滑膜NAS上,没有一个命令行版本对我有用。
下面是对命令每个部分的解释:
1 | find . -depth -name '*[A-Z]*' |
这将使用深度优先搜索(例如,它将在
这个命令本身对于首先查找要重命名的文件特别有用。在完成重命名命令后使用此命令搜索由于文件名冲突或错误而尚未被替换的文件。
1 | sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p' |
本部分读取
regex本身包含两个捕获:直到最后一个(文件的目录)的部分和文件名本身。目录保持不变,但文件名转换为小写。因此,如果
将它与
1 | sh |
这是不言自明的。它将所有生成的
如果使用arch linux,则可以从
它是快速重命名文件和目录的强大工具。
转换为小写1 | rename -l Developers.mp3 # or --lowcase |
转换为大写
1 | rename -u developers.mp3 # or --upcase, long option |
其他选项
1 2 3 4 5 6 7 8 9 10 11 | -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 # substite string on pattern --yes # Confirm all actions |
如果需要,可以从这里获取示例developers.mp3文件;)
< /块引用>没人建议打字?
1
2
3
4
5 typeset -l new # always lowercase
find $topPoint | # not using xargs to make this more readable
while read old
do mv"$old""$new" # quotes for those annoying embedded spaces
done在类似Git-Bash的Windows仿真中,这可能会失败,因为Windows在引擎盖下不区分大小写。对于这些,首先添加一个步骤,将mv作为文件名,比如"$old.tmp",然后添加到$new。
冗长但"工作时不会有意外,也不会安装"
此脚本处理带有空格、引号、其他不寻常字符和Unicode的文件名,适用于不区分大小写的文件系统和大多数安装了bash和awk的Unix-Y环境(即几乎所有)。它还报告冲突(如果有)(将文件名保留为大写),当然,重命名两个文件和目录并以递归方式工作。最后,它具有很强的适应性:您可以调整find命令以针对您希望的文件/目录,还可以调整awk以执行其他名称操作。注意,"handles unicode"的意思是它确实会转换它们的情况(不要像使用
tr 的答案那样忽略它们)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 # adapt the following command _IF_ you want to deal with specific files/dirs
find . -depth -mindepth 1 -exec bash -c '
for file do
# adapt the awk command if you wish to rename to something other than lowercase
newname=$(dirname"$file")/$(basename"$file" | awk"{print tolower(\$0)}")
if ["$file" !="$newname" ] ; then
# the extra step with the temp filename is for case-insensitive filesystems
if [ ! -e"$newname" ] && [ ! -e"$newname.lcrnm.tmp" ] ; then
mv -T"$file""$newname.lcrnm.tmp" && mv -T"$newname.lcrnm.tmp""$newname"
else
echo"ERROR: Name already exists: $newname"
fi
fi
done
' sh {} +工具书类
我的剧本基于这些优秀的答案:
https://unix.stackexchange.com/questions/9496/looping-through-files-with-spaces-in-the-names
如何在bash中将字符串转换为小写?
这也适用于MacOS:
1 ruby -e"Dir['*'].each { |p| File.rename(p, p.downcase) }"我需要在Windows7上的cygwin设置上执行此操作,并发现我在上面给出的建议中出现语法错误(尽管我可能错过了一个工作选项),但是这个直接从ubutu论坛获得的解决方案在can中成功了:-)
1 ls | while read upName; do loName=`echo"${upName}" | tr '[:upper:]' '[:lower:]'`; mv"$upName""$loName"; done(注意,我以前用下划线替换过空格
1 for f in *\ *; do mv"$f""${f// /_}"; done