重命名当前目录和子目录中的多个文件的脚本

重命名当前目录和子目录中的多个文件的脚本

该脚本应递归地遍历目录/子目录中的每个文件(跳过任何符号链接)并在文件名中进行以下替换:

  • 多个连续空格只有一个空格
  • 多个连续 _ 仅含一个 _
  • 一个或多个下划线后跟一个或多个空格(仅包含一个下划线)
  • 下划线后跟 - 仅带下划线
  • - 后跟下划线,只有下划线
  • 多个连续的“.”只有一个点
  • 使文件后缀全部小写(例如 .PdF 到 .pdf 这只是一个示例
  • 删除 @ 或 $ 或 ! 等字符

答案1

使用find和 perl rename

注意:perl在各种 Linux 发行版上rename也称为file-renameperl-rename、 或。不要与具有完全不同且不兼容的功能和命令行选项的实用程序prename混淆。renameutil-linux

find . -type f -print0 |
  rename -n -0 '
    s/[\@\$!]//g;            # remove all @, $, and ! characters.

    # remove leading and trailing whitespace (if any) from filenames
    s/^\s+|\s*\z//sg;

    # change all runs of any whitespace to just one space
    s/\s+/ /sg;

    s/[- ]*([._])[- ]*/$1/g; # remove space(s) and - around _ and .

    s/\.\.+/./g;             # reduce multiple periods to just one
    s/__+/_/g;               # reduce multiple _ to just one
    s/_*\._*/./g;            # change _. and ._ to just .

    s=(\.[^./]*\z)=lc($1)=e; # lowercase filename suffixes
'

第三种替换将连续的一个或多个空白字符(包括实际的空格字符、制表符、换行符、换页符等)替换为单个空格字符。 IMO,尽管它超出了您的要求,但替换文件名中所有不同类型的空白字符可能比仅替换空格字符更有用。如果这不是您想要的,请更改\s++(两个空格和一个)。+

第四个替换 ( s/[- ]*([_.])[- ]*/$1/g;) 假定您不需要在 或 之前有任何空格或_破折号.。这超出了您的要求,但如果超出您的实际需求,则很容易更改。

与此相关的是,倒数第二个替换仅将_.和替换为。这样您就不会得到像.如果您想要这样的文件名,请删除此行。._.foo_.bar_._pdf

最后一个替换中的正则表达式修饰符e导致替换被评估为 perl 代码 - 在本例中是函数lc(),它将其输入小写。

注意:重命名-n选项使其成为一次试运行,仅显示它将执行的操作。要实际重命名文件,请删除-n或将其更改-v为 以获得详细输出。

另请注意,如果您愿意(如果删除注释),多行重命名脚本可以压缩为一长的、几乎不可读的行(如果您删除注释#),但额外的换行和缩进使其更易于阅读和编辑,两者都在命令上行和脚本中。

最后,这假设当你说“浏览目录/子目录中的每个文件(跳过任何符号链接)”您还希望排除目录、设备节点、命名管道、套接字等重命名 - 即仅重命名常规文件。

如果您也想重命名匹配的目录,则必须-type ffind命令行上更改为\( -type f -o -type d \).

当然,您可以使用任何您喜欢的查找谓词来优化搜索。

答案2

有一个实用程序叫做排毒这可以解决您的许多问题。从网页:

  • 删除或替换大写 ASCII Latin-1 (ISO 8859-1) 字符(即向左和向右的双引号)。只要有可能,就会使用替换字符(即“A”将取代上面带有重音符号的“A”)。
  • 删除或替换 UTF-8 编码的 Unicode 字符。这与 ISO 8859-1 翻译的运作方式相同,只是 Unicode 的范围要大得多。
  • 删除或替换空格和其他可能棘手的字符,例如 (、) 和 @。删除文件名开头的所有“-”。
  • 删除或替换 CGI 转义 ASCII 字符,即 %20 变为“ ”(然后变为“_”)。
  • 修剪过多的“_”和“-”。
  • 目录递归、空运行、详细列表。
  • 它的设计考虑到了安全性。它不会覆盖已经存在的文件,并且通常不会触及特殊文件(但可以要求这样做)。

答案3

zsh

autoload -Uz zmv
zmv -n '(**/)(*)' '$1${${${${${2//[@\$!]}//[ _]##/_}//.##/.}//[-_]#_[-_]#/_}/%(#m).[^.]#/$MATCH:l}'

(高兴时删除-n以进行空运行)。

这是嵌套一些${param//pattern/replacemenet}运算符:

  • ${2//[@\$!]}:删除(文件的基本名称)@ $ !中的所有 s 。$2首先执行此操作,因为它可能会带来空间,_或者-我们需要在后续步骤中将其挤压在一起。
  • ${...//[ _]##/_}:在上述结果上,将一个或多个 ( ##) 空格或下划线的序列替换为_
  • ${...//.##/.}:在上述结果上,将一个或多个 ( ##)的序列替换..
  • ${...//[-_]#_[-_]#/_}:根据上述结果:删除 0 个或多个 ( #)_或任何带有-的两侧的。__
  • ${.../%(#m).[^.]#/$MATCH:l}:将末尾 ( ) 处的a.后跟一系列非s 替换为使用修饰符转换为小写的相同内容(使匹配在替换中可用)。.%(#m)$MATCH:l

zmv将首先处理目录深度(在它们所在的分支之前离开)并执行替换,在开始重命名之前进行一些健全性检查以确保没有数据丢失。

例如,这样做:

mv -- 'A _  - _  .. - b -c-d ..PDF' A_._b_c-d_.pdf

相关内容