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

2024-10-18 09:00:00
admin
原创
72
摘要:问题描述:我必须递归地重命名完整的文件夹树,以便任何地方都不会出现大写字母(这是 C++ 源代码,但这并不重要)。忽略 CVS 和 Subversion 版本控制文件/文件夹可获得加分。首选方式是使用 shell 脚本,因为任何 Linux 机器上都应该有 shell。关于文件重命名的细节有一些有效的论据。我...

问题描述:

我必须递归地重命名完整的文件夹树,以便任何地方都不会出现大写字母(这是 C++ 源代码,但这并不重要)。

忽略 CVS 和 Subversion 版本控制文件/文件夹可获得加分。首选方式是使用 shell 脚本,因为任何 Linux 机器上都应该有 shell。

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

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

  2. 我会考虑 AZ 字符并将它们转换为 az,其他一切都只是在引发问题(至少对于源代码而言)。

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


解决方案 1:

我还是比较喜欢小一点的:

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

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

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

解决方案 2:

使用以下命令的简洁版本"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

附言

后者允许移动命令具有更大的灵活性(例如"svn mv")。

解决方案 3:

如果您不需要关心效率,请简单尝试以下步骤。

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

解决方案 4:

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

注意:点是 macOS 兼容性所必需的,但它仍然适用于 Linux。

解决方案 5:

可以简单地使用以下不太复杂的方法:

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

解决方案 6:

我在 Mac OS X 上发现的最简单的方法是使用来自http://plasmasturm.org/code/rename/的重命名包:

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

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

--lower-case 将文件名全部转换为小写。

--nows 将文件名中的所有空格序列替换为单个下划线字符。

解决方案 7:

这适用于CentOS / Red Hat Linux或其他没有renamePerl 脚本的发行版:

for i in $( ls | grep [A-Z] ); do mv -i "$i" "`echo $i | tr 'A-Z' 'a-z'`"; done

来源:将所有文件名从大写字符重命名为小写字符

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

解决方案 8:

如果您已经拥有或设置了重命名命令(例如通过Mac 中的brew install ),则此方法有效:

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

解决方案 9:

上面的大多数答案都很危险,因为它们不处理包含奇数字符的名称。对于这种情况,最安全的做法是使用find选项-print0,它将使用 ASCII NUL 而不是 \n 来终止文件名。

这是一个脚本,它只改变文件名称而不改变目录名称,以免混淆find

find .  -type f -print0 | xargs -0n 1 bash -c \n'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:$\'/\'root:$\'/\'bin$\'/\'bash

... 猜猜看...

解决方案 10:

不可移植,仅适用于 Zsh,但非常简洁。

首先,确保zmv已加载。

autoload -U zmv

另外,请确保extendedglob已打开:

setopt extendedglob

然后使用:

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

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

解决方案 11:

以下是我的次优解决方案,使用 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”来搜索文件夹。

解决方案 12:

单行:

for F in K*; do NEWNAME=$(echo "$F" | tr '[:upper:]' '[:lower:]'); mv "$F" "$NEWNAME"; done

甚至:

for F in K*; do mv "$F" "${F,,}"; done

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

解决方案 13:

最初的问题要求忽略 SVN 和 CVS 目录,这可以通过在 find 命令中添加 -prune 来实现。例如忽略 CVS:

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

[编辑] 我试过了,在 find 中嵌入小写翻译不起作用,原因我不太明白。因此,将其修改为:

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

伊恩

解决方案 14:

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

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

解决方案 15:

这在 macOS 上也能很好地运行:

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

解决方案 16:

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

fix当然上面的脚本在哪里)

解决方案 17:

这是一个小型的 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 操作。

解决方案 18:

使用排版:

typeset -l new        # Always lowercase
find $topPoint |      # Not using xargs to make this more readable
  while read old
  do new="$old"       # $new is a lowercase version of $old
     mv "$old" "$new" # Quotes for those annoying embedded spaces
  done

在 Windows 上, Git Bash等模拟可能会失败,因为 Windows 不区分大小写。对于这些,请添加一个步骤,mv首先将文件更改为另一个名称,例如“$old.tmp”,然后再更改为$new

解决方案 19:

以下脚本适用于基于 RedHat 的系统,例如 RHEL、CentOS、Rocky 和 ​​Alma。

这里的所有解决方案都不适合我,因为我的系统无法访问 Perlrename脚本,而且我想要重命名的某些文件名包含空格(这在某些答案上存在问题)。但是,我找到了一种可行的变体:

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

感谢@“Gilles 'SO- stop being evil'”,在 Unix & Linux StackExchange 上查看类似问题将整个目录树更改为小写名称中的答案。

解决方案 20:

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

解决方案 21:

冗长但“无意外,无安装”

该脚本处理带有空格、引号、其他不常见字符和 Unicode 的文件名,适用于不区分大小写的文件系统和安装了 bash 和 awk 的大多数 Unix 环境(即几乎所有环境)。它还会报告任何冲突(将文件名保留为大写),当然还会重命名文件和目录并递归工作。最后,它具有高度的适应性:您可以调整 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

如何在 Bash 中将字符串转换为小写?

解决方案 22:

Slugify 重命名(正则表达式)

这并不是 OP 所要求的,但我希望在此页面上找到:

用于重命名文件的“slugify”版本,使其类似于 URL(即仅包含字母数字、点和破折号):

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

解决方案 23:

在 OS X 中,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

解决方案 24:

在这种情况下,我会使用 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])

解决方案 25:

如果您使用Arch Linux,则可以从中安装rename)包,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 # Substitute string on pattern

--yes # Confirm all actions

如果需要,您可以从这里获取示例Developers.mp3文件;)

解决方案 26:

使用 bash,无需rename

find . -exec bash -c 'mv $0 ${0,,}' {} ;

解决方案 27:

第一步

在 MacOS 上:

brew install rename

在Linux上:

sudo install rename

第二步

find . -depth -execdir rename -f 'y/A-Z/a-z/' {} ;

解释

find . -depth:确保以深度优先的方式处理目录。在重命名父目录之前重命名子目录时,避免出现问题非常重要。

$ tree -L 3                  
.
└── ACB
    ├── HUS
    └── TEXT.AA

$ find .
.
./ACB
./ACB/TEXT.AA
./ACB/HUS

$ find . -depth                                      
./ACB/TEXT.AA
./ACB/HUS
./ACB
.

-execdir rename 'y/A-Z/a-z/' {} ;:使用 Perl 表达式“y/AZ/az/”执行重命名命令。{}是目录名称的占位符,;标记选项的结束-execdir

$ find . -depth -execdir rename -f 'y/A-Z/a-z/' {} ;
# success
$ find .
.
./acb
./acb/text.aa
./acb/hus

解决方案 28:

( 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 ...-prune,因为它更简单。对于大型目录,for f in ...可能会溢出某些 shell 缓冲区。使用find ... | while read可以避免这种情况。

是的,这将破坏仅大小写不同的文件......

解决方案 29:

find . -depth -name '*[A-Z]*'|sed -n 's/(.*/)(.*)/mv -n -v -T  L/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  L/p'

此部分读取输出的文件并使用正则表达式find将其格式化为命令。该选项停止打印输入,搜索和替换正则表达式中的命令输出替换的文本。mv`-nsedp`

正则表达式本身由两个捕获组成:直到最后一个 /(即文件的目录)的部分和文件名本身。目录保持不变,但文件名将转换为小写。因此,如果find输出./FOO/BAR,它将变为mv -n -v -T ./FOO/BAR ./FOO/bar-n选项mv确保现有的小写文件不会被覆盖。-v选项会mv输出它所做的每项更改(或者不做 - 如果./FOO/bar已经存在,它会输出类似 的内容./FOO/BAR -> ./FOO/BAR,注意未进行任何更改)。-T这里的 非常重要 - 它将目标文件视为目录。这将确保如果该目录恰好存在,./FOO/BAR则不会将 移入。./FOO/bar

使用它find来生成将要执行的命令列表(方便验证将要执行的操作而无需实际执行)


sh

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

解决方案 30:

我需要在 Windows 7 上的 Cygwin 设置上执行此操作,但我发现我尝试了上述建议后出现了语法错误(尽管我可能错过了一个可行的选项)。不过,这个直接来自Ubuntu 论坛的解决方案却奏效了 :-)

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

(注意:我之前使用下划线替换了空格:

for f in * *; do mv "$f" "${f// /_}"; done

相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用