根据多种模式重命名文件的更好方法

2024-10-11 08:36:00
admin
原创
79
摘要:问题描述:我下载的很多文件的文件名中都有垃圾内容,例如[ www.crap.com ] file.name.extwww.crap.com - file.name.ext我想出了两种处理这些问题的方法,但它们看起来都很笨重:带参数扩展:if [[ ${base_name} != ${base_name//[+...

问题描述:

我下载的很多文件的文件名中都有垃圾内容,例如

[ www.crap.com ] file.name.ext

www.crap.com - file.name.ext

我想出了两种处理这些问题的方法,但它们看起来都很笨重:

带参数扩展:

if [[ ${base_name} != ${base_name//[+([^]])]} ]]
then
    mv -v "${dir_name}/${base_name}" "${dir_name}/${base_name//[+([^]])]}" &&
        base_name="${base_name//[+([^]])]}"
fi

if [[ ${base_name} != ${base_name//www.*.com - /} ]]
then
    mv -v "${dir_name}/${base_name}" "${dir_name}/${base_name//www.*.com - /}" &&
        base_name="${base_name//www.*.com - /}"
fi

# more of these type of statements; one for each type of frequently-encountered pattern

然后使用 echo/sed:

tmp=`echo "${base_name}" | sed -e 's/[[^][]*]//g' | sed -e 's/s-s//g'`
mv "${base_name}" "{tmp}"

我觉得参数扩展是两者中较差的,但我喜欢它,因为我能够在重命名后将相同的变量分配给文件以便进一步处理(上述代码用于在文件下载完成后为每个文件调用的脚本中)。

所以无论如何,我希望有一个更好/更干净的方法来完成上述操作,以便比我更有知识的人可以向我展示,最好以一种允许我轻松地将旧/原始变量重新分配给新/重命名文件的方式。

谢谢


解决方案 1:

两个答案:使用perl重命名或使用 狂欢

由于有些人不喜欢 perl,所以我编写了仅限 bash的版本

使用rename命令重命名文件。

介绍

是的,这是指挥的典型工作rename,其设计目的正是:

man rename | sed -ne '/example/,/^[^ ]/p'
   For example, to rename all files matching "*.bak" to strip the
   extension, you might say

           rename 's/.bak$//' *.bak

   To translate uppercase names to lower, you'd use

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

更多定向样本

只需删除所有空格方括号

rename 's/[ []]*//g;' *.ext

.jpg按编号重命名所有内容1

rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg

演示:

touch {a..e}.jpg
ls -ltr
total 0
-rw-r--r-- 1 user user 0 sep  6 16:35 e.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 d.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 c.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 b.jpg
-rw-r--r-- 1 user user 0 sep  6 16:35 a.jpg
rename 's/^.*$/sprintf "IMG_%05d.JPG",++$./e' *.jpg
ls -ltr
total 0
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00005.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00004.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00003.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00002.JPG
-rw-r--r-- 1 user user 0 sep  6 16:35 IMG_00001.JPG

以安全的方式匹配 SO 问题的完整语法

有一种使用实用程序的强大且安全的rename方法:

因为这是perl常用工具,我们要用到perl的语法:

rename 'my $o=$_;
        s/[ []]+/-/g;
        s/-+/-/g;
        s/^-//g;
        s/-(..*|)$/$1/g;
        s/(.*[^d])(|-(d+))(.[a-z0-9]{2,6})$/
                my $i=$3;
                $i=0 unless $i;
                sprintf("%s-%d%s", $1, $i+1, $4)
            /eg while
               $o ne $_  &&
               -f $_;
    ' *

测试规则:

touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext'
ls -1
[ www.crap.com ] file.name.ext
www.crap.com - file.name.ext
rename 'my $o=$_; ...
    ...
    ...' *
ls -1
www.crap.com-file.name-1.ext
www.crap.com-file.name.ext

touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext'
ls -1
www.crap.com-file.name-1.ext
[ www.crap.com ] file.name.ext
www.crap.com - file.name.ext
www.crap.com-file.name.ext
rename 'my $o=$_; ...
    ...
    ...' *
ls -1
www.crap.com-file.name-1.ext
www.crap.com-file.name-2.ext
www.crap.com-file.name-3.ext
www.crap.com-file.name.ext

... 等等...

...当您不使用-f标志rename命令时它是安全的:文件不会被覆盖,如果出现问题,您会收到一条错误消息。

使用重命名文件狂欢以及所谓的bashisms

我更喜欢使用专用实用程序来执行此操作,但这甚至可以通过使用 狂欢(又名无叉)

除了 bash 之外,没有使用任何其他二进制文件(没有sedawktr其他):

#!/bin/bash

for file;do
    newname=${file//[ ][]/.}
    while [ "$newname" != "${newname#.}" ] ;do
        newname=${newname#.}
      done
    while [ "$newname" != "${newname//[.-][.-]/.}" ] ;do
        newname=${newname//[.-][.-]/-};done
    if [ "$file" != "$newname" ] ;then
        if [ -f $newname ] ;then
            ext=${newname##*.}
            basename=${newname%.$ext}
            partname=${basename%%-[0-9]}
            count=${basename#${partname}-}
            [ "$partname" = "$count" ] && count=0
            while printf -v newname "%s-%d.%s" $partname $[++count] $ext &&
                  [ -f "$newname" ] ;do
              :;done
          fi
        mv  "$file" $newname
      fi
  done

以文件作为参数运行,例如:

/path/to/my/script.sh [*
  • 用点替换空格和方括号

  • 仅用一个替换.--.或序列。--`..`-

  • 测试文件名是否相同,如果相同则无需执行。

  • 测试文件是否存在且使用newname ...

  • 分割文件名、计数器和扩展名,用于制作索引新名称

  • 循环判断是否存在具有新名称的文件

  • 最后重命名文件。

解决方案 2:

利用以下经典模式:

 job_select /path/to/directory| job_strategy | job_process

负责job_select选择你的作业的对象,job_strategy为这些对象制定处理计划并job_process最终执行该计划。

这假设文件名不包含竖线|或换行符。

job_select 函数

 # job_select PATH
 #  Produce the list of files to process
 job_select()
 {
   find "$1" -name 'www.*.com - *' -o -name '[*] - *'
 }

find命令可以检查文件系统维护的文件的所有属性,如创建时间、访问时间、修改时间。还可以通过指示find不要深入到已安装的文件系统以及允许多少递归级别来控制文件系统的探索方式。通常会将管道附加到命令中,find以根据文件名执行更复杂的选择。

避免在函数输出中包含隐藏目录内容的常见陷阱job_select。例如,目录CVS.svn和由相应的源代码控制管理.svk工具.git使用,将它们的内容包含在函数输出中几乎总是错误的job_select。如果无意中批量处理这些文件,很容易使受影响的工作副本无法使用。

job_strategy 函数

# job_strategy
#  Prepare a plan for renaming files
job_strategy()
{
  sed -e '
    h
    s@/www..*.com - *@/@
    s@/[^]]* - *@/@
    x
    G
    s/
/|/
  '
}

此命令读取输出job_select并为我们的重命名作业制定计划。该计划由文本行表示,其中包含两个由字符分隔的字段|,第一个字段是文件的旧名称,第二个字段是文件的新计算文件,如下所示

[ www.crap.com ] file.name.1.ext|file.name.1.ext
www.crap.com - file.name.2.ext|file.name.2.ext

制定计划所用的特定程序本质上无关紧要,但通常使用sed示例;awkperl为此。让我们来看看sed这里使用的脚本:

h       Replace the contents of the hold space with the contents of the pattern space.
…       Edit the contents of the pattern space.
x       Swap the contents of the pattern and hold spaces.
G       Append a newline character followed by the contents of the hold space to the pattern space.
s/
/|/ Replace the newline character in the pattern space by a vertical bar.

使用多个过滤器来准备计划可能会更容易。另一个常见情况是使用命令stat将创建时间添加到文件名中。

job_process 函数

# job_process
#  Rename files according to a plan
job_process()
{
   local oldname
   local newname
   while IFS='|' read oldname newname; do
     mv "$oldname" "$newname"
   done
}

输入字段分隔符IFS经过调整,可让函数读取 的输出job_strategy。将oldname和声明newname为本地在大型程序中很有用,但在非常简单的脚本中可以省略。job_process可以调整函数以避免覆盖现有文件并报告有问题的项目。

关于 shell 程序中的数据结构
注意使用管道将数据从一个阶段传输到另一个阶段:初学者通常依靠变量来表示此类信息,但事实证明这是一个笨拙的选择。相反,最好将数据表示为表格文件或从一个进程移动到另一个进程的表格数据流,以这种形式,数据可以通过强大的工具(如、、sed和)轻松处理——仅列举最常见的工具。awk`joinpastesort`

解决方案 3:

您可以使用rnm

rnm -rs '/[crap]|[spam]//g' *.ext

上述操作将从文件名中删除[crap][spam]

您可以通过终止;或重载-rs选项来传递多个正则表达式模式。

rnm -rs '/[[]]//g;/s*[crap]//g' -rs '/crap2//' *.ext

此替换字符串的一般格式为/search_part/replace_part/modifier

  1. search_part:要搜索的正则表达式。

  2. replace_part:要替换的字符串

  3. 修饰符:i(不区分大小写)、g(全局替换)

大写/小写:

形式为的替换字符串/search_part/c/modifier将使文件名的选定部分(通过正则表达式search_part)变为小写,而C替换部分中的(大写 C)将使其变为大写。

rnm -rs '/[abcd]/C/g' *.ext
## this will capitalize all a,b,c,d in the filenames

如果您有许多需要处理的正则表达式模式,那么请将这些模式放在一个文件中并使用-rs/f选项传递该文件。

rnm -rs/f /path/to/regex/pattern/file *.ext

您可以在此处找到一些其他示例。

笔记:

  1. rnm 使用 PCRE2(修订的 PCRE)正则表达式。

  2. 您可以通过运行撤消不需要的重命名操作rnm -u

PS:我是这个工具的作者。

解决方案 4:

如果您使用的是 Ubunntu/Debian 操作系统,请使用 rename 命令一次重命名多个文件。

解决方案 5:

如果您想使用不依赖于 perl 的东西,您可以使用以下代码(我们称之为sanitizeNames.sh)。它只显示了几个案例,但可以使用字符串替换、tr(以及 sed)轻松扩展。

    #!/bin/bash

    ls $1 |while read f; do
      newfname=$(echo "$f" \n                  |tr -d '[ '     # Removing opened square bracket
                  |tr ' ]' '-'    # Translating closing square bracket to dash
                  |tr -s '-'       # Squeezing multiple dashes
                  |tr -s '.'       # Squeezing multiple dots
                )
      newfname=${newfname//-./.}

      if [ -f "$newfname" ]; then
        # Some string magic...
        extension=${newfname##*.}
        basename=${newfname%.*}
        basename=${basename%-[1-9]*}
        lastNum=$[ $(ls $basename*|wc -l) ] 
        mv "$f" "$basename-$lastNum.$extension"
      else
        mv "$f" "$newfname"
      fi
    done

并使用它:

    $ touch '[ www.crap.com ] file.name.ext' 'www.crap.com - file.name.ext' '[ www.crap.com ] - file.name.ext' '[www.crap.com ].file.anothername.ext2' '[www.crap.com ].file.name.ext'
    $ ls -1 *crap*
    [ www.crap.com ] - file.name.ext
    [ www.crap.com ] file.name.ext
    [www.crap.com ].file.anothername.ext2
    [www.crap.com ].file.name.ext
    www.crap.com - file.name.ext
    $ ./sanitizeNames.sh *crap*
    $ ls -1 *crap*
    www.crap.com-file.anothername.ext2
    www.crap.com-file.name-1.ext
    www.crap.com-file.name-2.ext
    www.crap.com-file.name-3.ext
    www.crap.com-file.name.ext
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   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源码管理

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

免费试用