如何在Linux上将所有文件夹和文件重命名为小写?
题
我必须递归地重命名一个完整的文件夹树,这样就不会出现任何大写字母(它是C ++源代码,但这无关紧要)。忽略CVS和SVN控制文件/文件夹的加分点。首选方法是shell脚本,因为shell应该可以在任何Linux机器上使用。
有一些关于文件重命名细节的有效论据。
-
我认为应该覆盖具有相同小写名称的文件,这是用户的问题。当在一个忽略大小写的文件系统上签出时,系统也会用后者覆盖第一个。
-
我会考虑A-Z字符并将它们转换为a-z,其他一切只是要求解决问题(至少使用源代码)。
-
在Linux系统上运行构建需要脚本,因此我认为应该省略对CVS或SVN控制文件的更改。毕竟,这只是一个划痕结账。也许是“出口”更合适。
醇>
解决方案
使用" rename"
命令的简明版本。
find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;
这避免了在文件之前重命名目录并尝试将文件移动到不存在的目录(例如" A / A"
into " a / a“
)。
或者,更简洁的版本,不使用" rename"
。
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上。
后者允许移动命令更灵活(例如" svn mv"
)。
其他提示
更小仍然非常喜欢
rename 'y/A-Z/a-z/' *
在不区分大小写的文件系统(如OS X的HFS +)上,您需要添加-f标志
rename -f 'y/A-Z/a-z/' *
for f in `find`; do mv -v "$f" "`echo $f | tr '[A-Z]' '[a-z]'`"; done
如果您不需要关心效率,只需尝试按照。
zip -r foo.zip foo/*
unzip -LL foo.zip
上面的大多数答案都很危险,因为它们不涉及包含奇数字符的名称。对于这类事情,你最安全的选择是使用find的-print0选项,它将使用ascii NUL而不是\ n来终止文件名。在这里我提交这个脚本,它只改变文件而不是目录名,以免混淆find。
find . -type f -print0 | xargs -0n 1 bash -c \
's=$(dirname "touch \;\ echo\ hacker::0:0:hacker:\$\'\057\'root:\$\'\057\'bin\$\'\057\'bash
")/$(basename "<*>");
d=$(dirname "<*>")/$(basename "<*>"|tr "[A-Z]" "[a-z]"); mv -f "$s" "$d"'
我测试了它,它适用于包含空格,各种引号等的文件名。这很重要,因为如果你以root身份运行树上包含由以下文件创建的文件的其他脚本之一:
<*>......好好猜测......
如果您已经拥有或设置重命名命令(例如通过Mac中的brew安装),则此功能正常运行:
rename --lower-case --force somedir/*
你们这些人喜欢让事情复杂化。
重命名'y / A-Z / a-z /'*
这适用于没有重命名
Perl脚本的CentOS / Redhat或其他发行版:
for i in $( ls | grep [A-Z] ); do mv -i "$i" "`echo $i | tr 'A-Z' 'a-z'`"; done
来源: https://linuxconfig.org/rename-全文件从 - 大写到小写字符
(在某些发行版中,默认的 rename
命令来自util-linux,这是一个不同的,不兼容的工具)
使用Larry Wall的文件名修复程序
$op = shift or die $help;
chomp(@ARGV = <STDIN>) unless @ARGV;
for (@ARGV) {
$was = 使用Larry Wall的文件名修复程序
find | fix 'tr/A-Z/a-z/'
就像
一样简单
<*>
(修正当然是上面的脚本)
;
eval $op;
die $@ if $@;
rename($was,使用Larry Wall的文件名修复程序
<*>
就像
一样简单
<*>
(修正当然是上面的脚本)
) unless $was eq 使用Larry Wall的文件名修复程序
<*>
就像
一样简单
<*>
(修正当然是上面的脚本)
;
}
就像
一样简单 <*>(修正当然是上面的脚本)
原始问题要求忽略SVN和CVS目录,这可以通过在find命令中添加-prune来完成。例如,忽略CVS:
find . -name CVS -prune -o -exec mv '{}' `echo {} | tr '[A-Z]' '[a-z]'` \; -print
[edit]我尝试了这一点,并且在查找中嵌入小写翻译并不是因为我实际上不理解的原因。所以,将其修改为:
<*>gt; cat > tolower
#!/bin/bash
mv $1 `echo $1 | tr '[:upper:]' '[:lower:]'`
^D
<*>gt; chmod u+x tolower
<*>gt; find . -name CVS -prune -o -exec tolower '{}' \;
伊恩
这是我的次优解决方案,使用bash Shell脚本:
#!/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控制文件仍然被重命名)。
编辑:自“找-depth”以来和“找到| sort -r“两者都以可用的顺序返回文件夹列表以进行重命名,我更喜欢使用“-depth”;用于搜索文件夹。
这是一个小shell脚本,可以执行您的请求:
root_directory="${1?-please specify parent directory}"
do_it () {
awk '{ lc= tolower(<*>); if (lc != <*>) print "mv \"" <*> "\" \"" lc "\"" }' | sh
}
# first the folders
find "$root_directory" -depth -type d | do_it
find "$root_directory" ! -type d | do_it
请注意第一次查找中的-depth操作。
以前发布的内容可以完美地开箱即用,或者针对简单案例进行一些调整,但在运行批量重命名之前,您可能需要考虑一些情况:
-
如果路径层次结构中的同一级别有两个或多个名称,只有大小写不同,例如
ABCdef
,abcDEF
,应该怎么办? <代码> ABCDEF 代码>?重命名脚本应该中止还是只是警告并继续? -
如何为非US-ASCII名称定义小写?如果可能存在此类名称,是否应首先执行检查和排除传递?
-
如果在CVS或SVN工作副本上运行重命名操作,则更改文件或目录名称的大小写可能会损坏工作副本。该脚本是否还应查找并调整内部管理文件,如.svn / entries或CVS / Entries?
醇>
for f in `find -depth`; do mv ${f} ${f,,} ; done
find -depth
打印每个文件和目录,并在目录本身之前打印目录的内容。 $ {f ,,}
小写文件名。
使用MacOS,
安装 rename
包,
brew install rename
使用,
find . -iname "*.py" -type f | xargs -I% rename -c -f "%"
此命令查找具有 * .py
扩展名的所有文件,并将文件名转换为小写。
`f` - forces a rename
例如,
$ 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
不便携,仅限Zsh,但非常简洁。
首先,确保已加载 zmv
。
autoload -U zmv
此外,请确保 extendedglob
已启用:
setopt extendedglob
然后使用:
zmv '(**/)(*)~CVS~**/CVS' '${1}${(L)2}'
以递归方式小写名称不是 CVS 的文件和目录。
在OSX中,mv -f显示“相同文件”。错误,所以我重命名两次。
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
我需要在Windows 7上的cygwin设置上执行此操作,发现我的语法错误与我尝试的上述建议有关(尽管我可能错过了一个工作选项)但是这个解决方案来自 ubutu论坛在罐子里工作: - )
ls | while read upName; do loName=`echo "${upName}" | tr '[:upper:]' '[:lower:]'`; mv "$upName" "$loName"; done
(我之前使用
替换了带下划线的空格for f in *\ *; do mv "$f" "${f// /_}"; done
在这种情况下我会达到python,以避免乐观地假设没有空格或斜线的路径。我还发现 python2
往往安装在比 rename
更多的地方。
#!/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])
冗长但是“与没有惊喜一起工作&amp;没有安装“
此脚本处理带有空格,引号,其他异常字符和Unicode的文件名,适用于不区分大小写的文件系统和大多数安装了bash和awk的Unix-y环境(即几乎所有)。它还会报告冲突(如果有的话)(将文件名保留为大写),当然还要重命名文件和文件。目录和递归工作。最后它具有很强的适应性:你可以调整find命令来定位你想要的文件/目录,你可以调整awk来做其他的名字操作。请注意,通过“处理Unicode”我的意思是它确实会转换它们的情况(不要忽略它们就像使用 tr
的答案一样)。
# 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(\<*>)}")
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 /循环贯通文件与 - 空间 - 内式名称
我在MacOSX上找到的最简单方法是使用 http://plasmasturm.org/code中的重命名包/重命名/ :
brew install rename
rename --force --lower-case --nows *
- 强制即使具有目标名称的文件已存在,也要重命名。
- 小写将文件名转换为全小写。
- nows用单个下划线字符替换文件名中的所有空白序列。
( 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 而不是找到...- prune ,因为它更简单。 对于大型目录, for f in ... 可能会溢出一些shell缓冲区。 使用 find ... |阅读以避免这种情况。
是的,这将是clobber文件,仅在案例中有所不同......
Slugify Rename(正则表达式)
不完全是OP所要求的,但我希望在此页面上找到的内容:
A“slugify”用于重命名文件的版本,因此它们与URL
类似
(即仅包括字母数字,点和短划线):
rename "s/[^a-zA-Z0-9\.]+/-/g" filename
如果您使用 Arch Linux ,则可以安装 重命名
包来自 AUR
,提供 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 # substite string on pattern
--yes # Confirm all actions
您可以从此处获取示例 Developers.mp3 文件,如果需要;)
没有人建议排版?
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。
这也适用于macOS:
ruby -e "Dir['*'].each { |p| File.rename(p, p.downcase) }"
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
命令输出替换的文本。
正则表达式本身包含两个捕获:直到最后一个/(文件目录)的部分,以及文件名本身。目录保持不变,但文件名转换为小写。因此,如果 find
输出 ./ FOO / BAR
,它将变为 mv -n -v -T ./FOO/BAR ./FOO/bar代码>。
mv
的 -n
选项可确保不覆盖现有的小写文件。 -v
选项使 mv
输出它所做的每次更改(或者不生成 - 如果 ./ FOO / bar
已经存在,它输出类似 ./ FOO / BAR - &gt; ./FOO/BAR
的内容,注意到没有进行任何更改)。 -T
在这里非常重要 - 它将目标文件视为目录。如果该目录恰好存在,这将确保 ./ FOO / BAR
不会移动到 ./ FOO / bar
。
与 find
一起使用以生成将要执行的命令列表(方便验证将在不实际执行的情况下执行的操作)
sh
这很不言自明。它将所有生成的 mv
命令路由到shell解释器。您可以将其替换为 bash
或您喜欢的任何shell。