shell脚本中有一种简便的字串提取方式,能够从类似test.doc中提取字符的文件名或者扩展名。
代码如下(选自linux shell脚本攻略)
$a=hack.func.book.txt
#提取文件名一
$echo ${a%.*}
hack.func.book
#提取文件名二
$echo ${a%%.*}
hack
#提取扩展名一
$echo ${a#(*.)}
func.book.txt
#提取扩展名二
$echo ${a##*.}
txt
刚开始比较费解,后面才懂。
其实上面的代码加个括号可读性更强,比如 $echo ${a%(.*)} $echo ${a##(.*)}
这种方法的提取思路其实有点绕,采用的减法思想,就是将匹配到的字符串去掉就剩下我想要的。比如abd.ds.cs.txt 我匹配了txt后删掉它,就是我的文件名了;同样我匹配了abd.ds.cs,去掉他们就剩下我的扩展名了。 而#和%是在控制匹配的方向,而双符号##和%%是在控制匹配的程度。
开始一个一个讲解
$a=hack.func.book.txt #我们要提取的字符串是这个
#提取文件名一
$echo ${a%(.*)} # 首先%确定我从右向左匹配,匹配满足.*的字串,就是左边一点右边随便是什么都行。于是
hack.func.book # 我从右往左找啊找,找到了第一个是.txt, 第二个是 .book.txt 第三个符合的字串是
# .func.book.txt 那么我匹配那一个呢?这时需要注意,我的%是不贪心的,匹配到第一个
# 时候我就高高兴兴收工了,好,我匹配到.txt了,然后我采取了减法思想,把他去掉,
# 就是hack.func.book了
#提取文件名二
$echo ${a%%(.*)} # %%要匹配的字符串和之前是一样的,也是.*,他从右往左匹配的方法和前者是一样的,也是
# 第一个.txt 第二个.book.txt 第三个.func.book.txt。 但是这货比较贪心,它要一直匹配
# 匹配到最后一个才收工,于是它匹配到了满足条件的最长的字串.func.book.txt,
# 好,下一步做掉它吧。于是就剩下 hack自己了。
#提取扩展名一
$echo ${a#(*.)} # #和%正好是相反的,#从左往右匹配,它要匹配像 *.这样的字符,也就是左边随便是什么
func.book.txt # 最后有个.点号的字串。于是它开始从左匹配了,先后匹配到hack.然后是hack.fun.然后
# 还有hack.func.book. 它也是不贪心的non-freedy,所以收工拿到的是hack.这个东西,最
# 后我们同样要将匹配到的删除,最后就剩下func.book.txt了
提取扩展名二
$echo ${a##(*.)} # ##则是从左向右很猛的进行匹配,匹配到hack.func.book. 因此删除他们的话,
txt # 就得到txt咯。
。。
一般写的代码是没有括号的,但是我觉得可读性不好,= =,直接导致我当时不能理解这货。 所以我自己觉得还是加上括号比较好,同时这样写的时候也利于自己的理解和分析。 不会乱的。