2.13 批量重命名和移动

重命名多个文件是我们经常会碰到的一项工作。举个简单的例子,当你把照片从数码相机传输到你的计算机之后,你可能会删除其中某些不如意的部分,这会使图像文件的编号变得不再连续。你会想使用特定的前缀和连续的数字对它们进行重命名。我们当然可以借助第三方软件执行这类重命名操作,但是也可以使用Bash命令在短短几秒钟之内完成同样的活儿。

另一件经常要做的工作是,将文件名中包含某个特定部分(例如相同的前缀)或者具有特定类型的所有文件移动到指定的文件夹中。让我们看看如何用脚本来执行这些操作。

2.13.1 预备知识

rename命令利用Perl正则表达式修改文件名。综合运用findrenamemv,我们能做到的事其实很多。

2.13.2 实战演练

用特定的格式重命名当前目录下的图像文件,最简单的方法是使用下面的脚本:

#!/bin/bash
#文件名: rename.sh
#用途: 重命名 .jpg 和 .png 文件

count=1;
for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1`
do
  new=image-$count.${img##*.}

  echo "Renaming $img to $new"
  mv "$img" "$new"
  let count++

done

输出如下:

$ ./rename.sh
Renaming hack.jpg to image-1.jpg
Renaming new.jpg to image-2.jpg
Renaming next.png to image-3.png

该脚本将当前目录下所有的 .jpg 和 .png 文件重命名,新文件名的格式为image-1.jpg、image-2.jpg、image-3.jpg、image-4.png等,依次类推。

2.13.3 工作原理

在前面的重命名脚本中,使用了for循环对所有扩展名为.jpg或.png的文件进行迭代。我们使用find命令进行搜索,选项-o用于指定多个-iname选项,后者用于执行大小写无关的匹配。借助-maxdepth 1,确保$img中只包含来自当前目录的文件名,无视其他的子目录。

为了跟踪图像编号,我们初始化变量count=1。下一步就是用mv命令重命名文件。因此需要构造出新的文件名。${img##*.}对处于当前循环中的文件名进行解析并获得文件扩展名(请参看2.12节中对于${img##*.}的解释)。

let count++用来在每次循环中增加文件编号。

还有许多其他执行重命名操作的方法,来看其中一些例子。

  • *.JPG更名为*.jpg

    $ rename *.JPG *.jpg
    
  • 将文件名中的空格替换成字符“_”:

    $ rename 's/ /_/g' *
    

    's/ /_/g'用于替换文件名,而*是用于匹配目标文件的通配符,它也可以以*.txt或其他样式出现。

  • 转换文件名的大小写:

    $ rename 'y/A-Z/a-z/' *
    $ rename 'y/a-z/A-Z/' *
    
  • 将所有的 .mp3文件移入给定的目录:

    $ find path -type f -name "*.mp3" -exec mv {} target_dir \;
    
  • 将所有文件名中的空格替换为字符“_”:

    $ find path -type f -exec rename 's/ /_/g' {} \;