在linux中批量处理文件名,是十分容易的操作。有多种方法与手段,如mv、rename、prename、sed和awk等。我们前面两篇文章《linux centos7中批量修改文件名》和《awk批量修改文件名》进行了讨论。可供参考。
本文从学习bash变量和变量子串操作为基础,从批量处理文件名为项目上,讨论分支语句和循环语句。
一、相关变量和代码
1.变量
bash中的变量是bash命令与编程的基础。
定义与应用
不用事先声明,直接使用。
变量不分数据类型,均以字符串为标准。
变量定义 变量名=变量值,如name=zhang3;age=18
打印变量 echo $name 或者 echo ${age}
双方括号: [[ ]]
用于字符串比较的正则匹配, 用于变量的模糊匹配与精确匹配。
变量子串
格式:${变量}
主要的作用:变量子串的效率要比相应的命令执行的效率高
变量的长度 ${#变量}
变量子串截取
打印指定开始位置的字符串长度,${变量:3}
从第三个字符到结尾保留(包含空格且不算第三个字符)
也可以制定从哪个字段开始取,取多少字段 ${变量:3:5}
变量子串匹配删除
#表示从开头删除匹配最短
##表示从开头删除匹配最长
%表示从结尾删除匹配最短
%%表示从结尾删除匹配最长
变量子串替换
使用/代替第一个指定匹配的字符并替换
使用//代替所有匹配的指定字符串
2.分支语句
正常命令的执行顺序都是从前向后依序执行。只有当使用分支语句时,可以改变代码执行的方向与前后顺序。
分支语句是编程里的一个基础且重要的语法语句,执行的路径会被分成两条,再加上限制条件或者判定条件,将执行不同的代码,有if语句、else、switch语句、defualt子句。
分支分类
a.单分支
if [ ];then fi
b.双分支
if [ ];then else fi
c.多分支
if [ ];then elif else fi
3.循环语句
循环语句有重要的几类:for while do while until switch case等。
最常用的是for和while。
for命令是linux自带的命令,能够实现对文件或者目录的批量重命名。
for命令的一般格式:
for file in files_list; do command;done
files_list表示准备重命名的文件或者目录的列表,command表示要执行的命令,该命令不仅可以用来实现文件或者目录的批量重命名,还能实现即时重命名文件和目录,当前文件或者目录依然保持完整。
循环之间可以嵌套,循环与分支配合,应用广泛。
我们说,for循环是一切编程的基础;单条命令是基础,多项组合构成脚本,分支语句与循环语句的巧妙运用,完成一个项目上。深刻理解命令是一批系统调用的集合,人机交互的抓手,bash或shell是常用的支架或工具。
二、项目训练
1.思路
在项目中学习命令与流程控制。
批量处理文件名,离不开循环。而for循环是最主要的!
本文的主要目的:通过for循环使用与训练,抓住问题的关键,寻根问底,追求举一反三。
在解决项目的过程中,用到多个命令,每项命令又有很多选项,其参数也有变化。只有多用多练命令,才可处理复杂的棘手问题。
2.for循环的原理
a.解决文件的表达
查出文件,或列表显示文件
b.选择命令的使用
可选择ls ll,也可以选择find grep等
c.循环条件的设计
循环常用for和while。我们主要选择for。
for file in `ls *.conf`; do mv $file ${file%.*}.cpp;done
代码作用是批量修改后缀.conf为后缀.cpp
3.具体案例
批量处理文件名,主要是对原有文件名的增删改。其中涉及后缀、路径和文件名。
a、替换
改变文件的后缀,是常见的工作需要,也是最简单的修改。
b、添加
ps:linux下批量改变文件前缀命令
for f in * ; do mv -- "$f" "PRE_$f" ; done
包括在后缀后再添加后缀,前缀前再加前缀,文件名中添加标志性字符。
c、修改
有的文件名添加有多项说明性文字或日期或项目编号等,一定条件下,需要变为其他名称。
d、组合
添加前后缀与标志性关键词,删除不需要的术语或编号,多项要求与组合。
e、拆分
有些符号或标志不合适,更改为新的符号。
具体案例要求前两篇文章相同,以不同的方法与思路,解决同一个问题。
1.把当前目录下的.conf文件全部修改为.txt文件
2.把当前目录下的test开头的文件全部修改为demo开头的文件
3.调整当前目录下子目录下的2022-05-01等含日期的文件为_分隔的文件
4.将当前目录下所有子目录下以a开头的.cpp文件修改为以b开头的.c文件
5.将当前目录下所有子目录下以ab开头的.sh文件修改为以AB开头的.py文件,并将所有.jpg文件修改为test_01.jpg等格式(序号按修改文件时间排列)
4.代码与说明
查找当前目录下文件
ls *.conf
形成文件列表
`ls *.conf`
或者$(ls *.conf)
可以赋值给一个变量lt=`ls *.conf`
设计一个for循环:
for f in lt
do
循环代码
done
查找当前目录下文件及子目录下文件
find ./ -name “*.conf”
如果是查询两个后缀的文件
find ./ -name “*.conf” -o –name “*.txt”
如果是查询多个后缀的文件(建议用扩展正则)
find ./ -regextype posix-extended -regex “*\.\(conf|txt|cpp\)”
改变文件后缀
a.创建一个新变量,接收重命名的文件
newfile=`echo $f |rename .conf .txt`
newfile=`echo $f |sed 's/.conf/.txt/'`
mv -f $f $newfile
b.在用mv重命名时,修改变量子串
mv -f $f ${f%.*}.txt
建议:简单修改文件名后缀,用b方法;一般性修改文件名,用a方法。
修改前缀
把当前目录下的test开头的文件全部修改为demo开头的文件
同前一案例,两个方法均可(不论调整何处的字符串都可以)
for f in $(ls test*)
do
mv -f $f ${f/test/demo}
done
如何处理当前目录及子目录下的文件,可以改ls查找文件为find命令,多路径查找。
对于替换首字符或首单词情况,可以如此处理:
for f in $(ls test*)
do
mv -f $f "demo"${f:4}
done
$(f:4)表示保留原变量的第4位至尾部字符
调整格式
调整当前目录下子目录下的2022-05-01等含日期的文件为_分隔日期的文件
与前两类案例相比,增加一点难度:
把单次替换改为全局替换!用变量子串时,用双/(//);用sed替换时,格式为's///g'
for f in `find ./ -name "*-??-*"`
do
mv -f $f ${f//-/_}
done
高难度修改
将当前目录下所有子目录下以a开头的.cpp文件改名为以b开头的.c文件
本案例有难度,但通过前述两个方法的组合,可以解决。
for f in `find ./ -name "a*.cpp"`
do
newfile=`echo $f | sed 's/.cpp/.c/'`
mv -f $f ${newfile/a/b}
done
相互交换一下才成立。
for f in `find ./ -name "b*.c"`
do
newfile=`echo $f | sed 's/b/a/'`
mv -f -v $f ${newfile%.*}.cpp
done
-f 强制修改
-v 显示过程
复杂修改
将当前目录下所有子目录下以ab开头的.sh文件修改为以AB开头的.py文件,并将所有.jpg文件修改为test_01.jpg等格式(序号按修改文件时间排列)
这是较为复杂的案例。主要是使用分支语句:
分支1 处理.sh文件
分支2 处理.jpg文件
操作实践表明:同时处理两类文件时,不能使用双分支语句,多分支语句更无法使用。
另外,在对两个变量进行模糊匹配时,只能把文件名变量放在前面,文件名后缀作为变量,只能放在后面。
基本格式:
if [[ $f =~ $a ]];then
echo $f
echo ++++++++++++
mv $f "prefix_"${f%.*}.jpg
fi
如果在变量中添加序列类数字,需要在for循环前定义变量x,循环时添加x++
x=0
for f in `ls ab*.sh *.jpg`
do
a=".sh"
b=".jpg"
if [[ $f =~ $a ]];then
newfile=`echo $f | sed 's/py/sh/'`
mv $f "AB"${f#ab}
fi
if [[ $f =~ $b ]];then
let x++
mv $f test$x".jpg"
fi
done