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

时间:2008-09-30 10:25:18

标签: linux rename lowercase

我必须递归地重命名一个完整的文件夹树,这样就不会出现任何大写字母(它是C ++源代码,但这无关紧要)。忽略CVS和SVN控制文件/文件夹的加分点。首选方法是shell脚本,因为shell应该可以在任何Linux机器上使用。

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

  1. 我认为应该覆盖具有相同小写名称的文件,这是用户的问题。当在一个忽略大小写的文件系统上签出时,系统也会用后者覆盖第一个。

  2. 我会考虑A-Z字符并将它们转换为a-z,其他一切只是要求解决问题(至少使用源代码)。

  3. 在Linux系统上运行构建需要脚本,因此我认为应该省略对CVS或SVN控制文件的更改。毕竟,这只是一个划痕结账。也许“出口”更合适。

29 个答案:

答案 0 :(得分:236)

更小仍然非常喜欢

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

在不区分大小写的文件系统(如OS X的HFS +)上,您需要添加-f标志

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

答案 1 :(得分:160)

使用"rename"命令的简明版本。

find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

这可以避免在文件之前重命名目录并尝试将文件移动到不存在的目录(例如"A/A""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")。

答案 2 :(得分:82)

for f in `find`; do mv -v "$f" "`echo $f | tr '[A-Z]' '[a-z]'`"; done

答案 3 :(得分:66)

如果您不需要关心效率,只需尝试按照。

zip -r foo.zip foo/*
unzip -LL foo.zip

答案 4 :(得分:14)

上面的大多数答案都很危险,因为它们不涉及包含奇数字符的名称。对于这类事情,你最安全的选择是使用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"'

我测试了它,它适用于包含空格,各种引号等的文件名。这很重要,因为如果你以root身份运行树上包含由以下文件创建的文件的其他脚本之一:

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

......好好猜测......

答案 5 :(得分:12)

如果您已经拥有或设置重命名命令(例如通过Mac中的brew安装),则此功能正常运行:

rename --lower-case --force somedir/*

答案 6 :(得分:10)

你们这些人喜欢让事情复杂化。

重命名'y / A-Z / a-z /'*

答案 7 :(得分:6)

这适用于没有rename 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-all-files-from-uppercase-to-lowercase-characters

(在某些发行版中,默认的rename命令来自util-linux,这是一个不同的,不兼容的工具)

答案 8 :(得分:4)

原始问题要求忽略SVN和CVS目录,这可以通过在find命令中添加-prune来完成。例如,忽略CVS:

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

[edit]我尝试了这一点,并且在查找中嵌入小写翻译并不是因为我实际上不理解的原因。所以,将其修改为:

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

伊恩

答案 9 :(得分:4)

使用Larry Wall的文件名修复程序

$op = shift or die $help;
chomp(@ARGV = <STDIN>) unless @ARGV;
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}

就像

一样简单
find | fix 'tr/A-Z/a-z/'

(修正当然是上面的脚本)

答案 10 :(得分:4)

这是我的次优解决方案,使用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控制文件仍然被重命名)。

编辑:由于“find -depth”和“find | sort -r”都以可用的顺序返回文件夹列表进行重命名,我更喜欢使用“-depth”来搜索文件夹。

答案 11 :(得分:3)

这是一个小shell脚本,可以执行您的请求:

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

请注意第一次查找中的-depth操作。

答案 12 :(得分:2)

以前发布的内容可以完美地开箱即用,或者针对简单案例进行一些调整,但在运行批量重命名之前,您可能需要考虑一些情况:

  1. 如果您在路径层次结构中的同一级别有两个或多个名称,仅根据具体情况而有所不同,例如ABCdefabcDEFaBcDeF,会发生什么?重命名脚本应该中止还是只是警告并继续?

  2. 如何为非US-ASCII名称定义小写?如果可能存在此类名称,是否应首先执行检查和排除传递?

  3. 如果在CVS或SVN工作副本上运行重命名操作,则在更改文件或目录名称的大小写时可能会损坏工作副本。该脚本是否还应查找并调整内部管理文件,如.svn / entries或CVS / Entries?

答案 13 :(得分:2)

使用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

答案 14 :(得分:2)

for f in `find -depth`; do mv ${f} ${f,,} ; done

find -depth打印每个文件和目录,目录的内容在目录本身之前打印。 ${f,,}小写文件名。

答案 15 :(得分:1)

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

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

-force即使具有目标名称的文件已经存在,也要重命名。

     

-小写将文件名转换为小写。

     

-现在用单个下划线字符替换文件名中的所有空白序列。

答案 16 :(得分:1)

在OSX中,mv -f显示&#34;相同的文件&#34;错误,所以我重命名两次。

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

答案 17 :(得分:1)

很长但是“没有任何惊喜,没有安装的作品”

此脚本处理带有空格,引号,其他不寻常字符和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(\$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

How to convert a string to lower case in Bash?

答案 18 :(得分:1)

在这种情况下我会达到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])

答案 19 :(得分:1)

不便携,仅限Zsh,但非常简洁。

首先,确保已加载zmv

autoload -U zmv

另外,请确保extendedglob已开启:

setopt extendedglob

然后使用:

zmv '(**/)(*)~CVS~**/CVS' '${1}${(L)2}'

以递归方式小写名称不是 CVS 的文件和目录。

答案 20 :(得分:0)

Slugify Rename(正则表达式)

不完全是OP所要求的,但我希望在此页面上找到的内容:

用于重命名文件的“slugify”版本,因此它们类似于URL (即仅包括字母数字,点和短划线):

rename "s/[^a-zA-Z0-9\.]+/-/g" filename

答案 21 :(得分:0)

如果您使用Arch Linux,则可以从rename安装AUR个软件包,该manual个软件包提供$(document).on("click", ".cc-form-control-switcher .btn-first, .cc-form-control-switcher .btn-second" ,function(e) { e.preventDefault(); var $self = $(this); var $siblingSelected = $self.parent().find(".btn-switch"); $siblingSelected.removeClass("btn-switch"); $self.addClass("btn-switch"); var hdnField = $self.parent().find("input[type=hidden]"); if (hdnField.length > 0) { hdnField.val($self.data("value")); } }); 可执行文件的renamexm命令及其here页面连同它。

它是快速重命名文件和目录的强大工具。

转换为小写

/usr/bin/renamexm

转换为大写

rename -l Developers.mp3 # or --lowcase

其他选项

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

如果需要,您可以从enter image description here获取示例 Developers.mp3 文件;)

答案 22 :(得分:0)

没有人建议排版?

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。

答案 23 :(得分:0)

我需要在Windows 7上的cygwin设置上执行此操作,发现我在上面提出的建议中遇到了语法错误(尽管我可能错过了一个工作选项)但是这个解决方案来自{{3}在罐子里工作: - )

ls | while read upName; do loName=`echo "${upName}" | tr '[:upper:]' '[:lower:]'`; mv "$upName" "$loName"; done

(我之前使用

替换了带下划线的空格
for f in *\ *; do mv "$f" "${f// /_}"; done

答案 24 :(得分:0)

这在macOS上也很好:

ruby -e "Dir['*'].each { |p| File.rename(p, p.downcase) }"

答案 25 :(得分: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后跟{{ 1}},将./FOO/BAR重命名为./FOO仍将继续列出./foo,即使该路径不再有效)。上面的命令对我没有任何问题。

以下是该命令各部分的说明:


./FOO/BAR

这将使用深度优先搜索(例如,它将在{{1之前列出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的{​​{1}}选项可确保不会覆盖现有的小写文件。 mv -n -v -T ./FOO/BAR ./FOO/bar选项使-n输出所做的每个更改(或不进行更改-如果mv已经存在,则输出类似-v的内容,请注意没有更改已完成)。 mv在这里非常重要-将目标文件视为目录。如果该目录恰好存在,这将确保不会将./FOO/bar移到./FOO/BAR -> ./FOO/BAR中。

-T结合使用以生成将要执行的命令列表(方便地验证将要执行的命令而不实际执行)


./FOO/BAR

这很不言自明。它将所有生成的./FOO/bar命令路由到Shell解释器。您可以将其替换为find或自己喜欢的任何外壳。

答案 26 :(得分:0)

( 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文件,仅在案例中有所不同......

答案 27 :(得分:0)

这里的所有解决方案都不适合我,因为我所在的系统无法访问perl重命名脚本,而且某些文件中包含空格。但是,我发现了一个可行的变体:

find . -depth -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

贷方转到“吉尔斯'SO-别再作恶了”,请参阅this answer on the similar question "change entire directory tree to lower-case names" on the Unix & Linux StackExchange

答案 28 :(得分:0)

单线:

    DECLARE
        mycounter NUMBER := 0;
    BEGIN
        SELECT count(*)
        INTO mycounter
        FROM SCHEDULE S
        WHERE S.StartTime<=12
        AND S.EndTime>=22
        AND S.DAY='21 November';
    
        IF mycounter > 0 THEN
            UPDATE SCHEDULE 
            SET EndTime=22  
            WHERE EndTime=12 AND Day='21 November'
        END IF;
    END;
    /

请注意,这只会转换以字母K开头的文件/目录,因此请进行相应调整。