故事背景
故事描述
最近被问到如何在Linux环境下对文件进行批量重命名,仔细想了一下,好像平时也没关注过这个的写法,之前有过类似需求时,作为一个Python开发者,更多地会想到直接用写Python脚本去处理,虽然知道可能可以通过shell脚本或者有直接的Linux命令去做,但一直没试过,决定写这篇文章整理下
系统配置
操作系统
1 | cat /proc/version |
Linux version 4.13.0-45-generic (buildd@lgw01-amd64-011) (gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)) #50~16.04.1-Ubuntu SMP Wed May 30 11:
故事经过
综述
针对这个问题,根据以往经验,以及网上搜索相关信息,和自己试验,大概可以通过Linux命令、shell脚本、Python脚本来解决
首先,在本地touch了几个以不同后缀名结尾的文件,现在希望将.png格式全部替换为.jpg
1 | ls |
1 | total 8 |
Linux命令
通过搜索,使用rename命令可以实现单一命令批量重命名
先看一下rename命令的文档
1 | man rename |
RENAME(1p) User Contributed Perl Documentation RENAME(1p)
NAME rename - renames multiple files
SYNOPSIS rename [ -h|-m|-V ] [ -v ] [ -n ] [ -f ] [ -e|-E perlexpr]*|perlexpr [ files ]
DESCRIPTION "rename" renames the filenames supplied according to the rule specified as the first argument. The perlexpr argument is a Perl expression which is expected to modify the $_ string in Perl for at least some of the filenames specified. If a given filename is not modified by the expression, it will not be renamed. If no filenames are given on the command line, filenames will be read via standard input.
For example, to rename all files matching "*.bak" to strip the extension, you might say rename 's/\e.bak$//' *.bak To translate uppercase names to lower, you'd use rename 'y/A-Z/a-z/' *
OPTIONS -v, -verbose Verbose: print names of files successfully renamed.
-n, -nono No action: print names of files to be renamed, but don't rename. -f, -force Over write: allow existing files to be over-written. -h, -help Help: print SYNOPSIS and OPTIONS. -m, -man Manual: print manual page. -V, -version Version: show version number. -e Expression: code to act on files name. May be repeated to build up code (like "perl -e"). If no -e, the first argument is used as code. -E Statement: code to act on files name, as -e but terminated by ';'.
ENVIRONMENT No environment variables are used.
AUTHOR Larry Wall
SEE ALSO mv(1), perl(1)
DIAGNOSTICS If you give an invalid Perl expression you'll get a syntax error.
BUGS The original "rename" did not check for the existence of target filenames, so had to be used with care. I hope I've fixed that (Robin Barker).
perl v5.20.2 2015-06-05
根据需求,可以通过正则表达式 s/.png/.jpg/ 实现
先用-n命令打印下重命名的范围
1 | rename -n 's/.png/.jpg/' *.png |
1 | rename(a1.png, a1.jpg) |
可以看到,能够完美地满足我们的需求,于是去掉-n命令,再次执行
1 | rename 's/.png/.jpg/' *.png |
再次查看当前目录下文件
1 | ls -al |
1 | total 8 |
可以看到需求完全满足,搞定
Shell脚本
提到重命名单个文件,最先想到的就是 mv 命令,于是试验下能否直接通过mv命令批量重命名文件
1 | mv *.jpg *.png |
mv: target '*.png' is not a directory
运行报错了,看来不支持这么玩,于是写个shell脚本来循环遍历吧
1 | !/bin/bash |
这个命令比较简单,循环遍历所有.jpg文件,执行mv指令,将文件mv成以.png结尾的文件
执行脚本
1 | sh rename_file.sh |
1 | total 12 |
可以看到,所有的*.jpg文件都被替换为了.png文件
抱着好奇的心态,此时我再次尝试执行此脚本,结果报错了
ls: cannot access '*.jpg': No such file or directory
可以看到,ls中因为没找到.jpg文件所以报错了,由于我有点强迫症,于是我想试着修改下,避免这种报错
方便起见,我先利用此前的rename命令将文件还原为.jpg结尾的
1 | rename 's/.png/.jpg/' *.png |
将shell脚本替换为
1 | !/bin/bash |
此时执行后,
1 | total 12 |
可以看到,批量重命名文件的需求时达到了的,再次执行此脚本,没有任何报错信息,搞定
Python脚本
说起Python,首先也是先遍历当前目录,os.listdir()即可满足此需求,之后通过检查源字符串是否存在文件名中,将其使用replace命令替换成新的文件名,至于文件重命名,用shutil.move即可,此功能类似mv命令
1 | import os |
故事结尾
经过一系列的查资料和试验,原以为的Python虽然理解起来和写起来都很轻松,但是这种事还是交给专业做这个的Linux命令和Shell脚本比较好,Linux中文件操作问题尽量还是用原生方法更好