正则文本处理

文本处理常用命令grep cut awk sed:

date时间

[dispatcher@ip-172-31-14-16 log]$ date +%T
16:20:51
[dispatcher@ip-172-31-14-16 log]$ date +%Y:%T
2019:16:20:57
[dispatcher@ip-172-31-14-16 log]$ date -d "-10min" +%T
16:11:11
[dispatcher@ip-172-31-14-16 log]$ date -d "-1day" +%Y:%m:%d
2019:06:12
[dispatcher@ip-172-31-14-16 log]$ date -d "-1day" +%Y:%m:%d:%H:%M:%S
2019:06:12:16:21:31
[dispatcher@ip-172-31-14-16 log]$ date -d "-5 minute" +%H:%M:%S
16:18:47
[dispatcher@ip-172-31-14-16 log]$ date -d "-5min" +%H:%M:%S
16:18:55

cat 查看文件内容:

-b 显示行号,空白行不显示行号

-n 显示行号,包括空白行

more 分页查看文件内容,通过空格键查看下一页,q键则退出查看

less 分页查看文件内容,空格(下一页),方向键(上下回键),q键(退出查看)

head 查看文件头部内容,默认显示前10行:

-c nK 显示文件前nKB的内容

-c  n  显示内容前n个字节

-n  显示文件前n行的内容

head -c 2K /root/install.log 查看文件前2KB的内容

head -20 /root/install.log  查看文件前20行的内容

tail 查看文件的尾部内容,默认显示末尾10行:

-c nK 显示文件末尾nKB的内容

-n 显示文件末尾n行的内容

-f 动态显示文件内容,按Ctrl+C组合键退出

tail -c 2K /root/install.log 查看文件末尾2KB的内容

tail -20 /root/install 查看文件末尾20行的内容

tail -f /var/log/messages 实时查看文件内容

wc 显示文件的行、单词与字节的统计信息:

-c 显示文件字节统计信息

-l 显示文件行数统计信息

-w 显示文件单词统计信息

sort 对文件内容进行排序

语法:
sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符>][+<起始栏位>-<结束栏位>][--help][--verison][文件]

-b:忽略每行前面开始的空格字符,空格数量不固定时,该选项几乎是必须要使用的("-n"选项隐含该选项,测试发现都隐含)
-c:检查文件是否已经按照顺序排序,如未排序,会提示从哪一行开始乱序
-C:类似于"-c",只不过不输出任何诊断信息。可以通过退出状态码1判断出文件未排序
-d:只处理英文字母、数字及空格,忽略其他的字符
-f:将小写字母视为大写字母
-h:使用易读性数字(例如:2K、1G)
-i:除了040至176之间的ASCII字符外(八进制0-177),忽略其他的字符(忽略无法打印的字符如退格/换页键/回车)
-k:以哪个区间 (field) 来进行排序
-m:将几个排序好的文件进行合并,只是单纯合并,不做排序
-M:将前面3个字母依照月份的缩写进行排序
-n:依照数值的大小排序
-o<输出文件>:将排序后的结果存入指定的文件
-r:降序
-u:忽略相同行
-t<分隔字符>:指定分隔符,默认的分隔符为空白字符和非空白字符之间的空字符

grep:

-i 是忽略大小写  --color 是加颜色

-n  是输出行号  (同 cat -n)

-w 精准匹配

-ra 深度查找匹配

-E  是grep 的 扩展

^    是以什么开始

$    是以什么结尾

o    只打印出匹配到的关键字,而不打印出整行

egrep相当于 grep -E

-v    是反选

grep Aug /var/log/messages 在文件 ‘/var/log/messages’中查找关键词”Aug” 

grep ^Aug /var/log/messages 在文件 ‘/var/log/messages’中查找以”Aug”开始的词汇 

grep --color "[0-9]" /var/log/messages 选择 ‘/var/log/messages’ 文件中所有包含数字的行 

grep --color "[0-9][0-9][0-9]" /var/log/messages  选择 ‘/var/log/messages’ 文件中所有的数字连续匹配3次

grep -E --color "[0-9]{4}"  /var/log/messages  选择 ‘/var/log/messages’ 文件中所有数字的行能连续匹配4次

grep -E --color "[0-9]{1,3}"  /var/log/messages  选择 ‘/var/log/messages’ 文件中所有数字的行能连续匹配1到3次

netstat -lnutp | egrep -o "[0-9]+\/java"|egrep -o "[0-9]+"  取出所有java的进程id

grep --color "[a-z]" /var/log/messages

grep --color "[A-Z]" /var/log/messages

grep --color "[Aa-Zz]" /var/log/messages

grep Aug -R /var/log/* 在目录 ‘/var/log’ 及随后的目录中搜索字符串”Aug”

grep -i --color "com" test.txt  在test.txt文件里忽略大小写搜索“com”并颜色显示

grep -i -n --color "com" test.txt  在test.txt文件里忽略大小写搜索“com”,显示所在行号并颜色显示

egrep -n --color "[0-9]" /etc/passwd    显示/etc/passwd里所有内容的行号

grep -v "root" /etc/passwd  显示文件中root之外的所有内容(反选)

grep -v "^$" test.txt    去掉文件里的空行

grep -v "^#" test.txt   去掉文件里的注释行

egrep -v "^#|^$" test.txt   去掉文件里的注释行和空行

sed:

选项与参数:
-n :使用安静(silent)模式,加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来,但不会真正去修改原文件。
-e :直接在命令列模式上进行 sed 的动作编辑;
-f :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作;
-r :sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)
-i :直接修改读取的文件内容,而不是输出到终端。
function:
a :新增行, a 的后面可以是字串,而这些字串会在新的一行出现(目前的下一行)
c :取代行, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行
d :删除行,因为是删除,所以 d 后面通常不接任何参数,直接删除地址表示的行;
i :插入行, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行
s :替换,可以直接进行替换的工作,通常这个 s 的动作可以搭配正规表示法,例如 1,20s/old/new/g 一般是替换符合条件的字符串而不是整行

^ 匹配行开始,如:/^sed/匹配所有以sed开头的行。
$ 匹配行结束,如:/sed$/匹配所有以sed结尾的行。
$= 匹配结尾的行数,如 sed -n "$=" /var/log/messsage.
. 匹配一个非换行符的任意字符,如:/s.d/匹配s后接一个任意字符,最后是d。
* 匹配0个或多个字符,如:/*sed/匹配所有模板是一个或多个空格后紧跟sed的行。

sed -i '/192.168.1.115/d' awk.text   直接删除文件内的192.168.1.115

sed -i 's/192.168.1.115/192.168.1.114/g' awk.text    直接修改文件内的192.168.1.115为114

sed -i 's/serername/servername:/g' awk.text

sed -i '3s/serername/servername:/g' awk.text    修改文件种第3行(修改第几行在s前面加上修改的行数,不加默认全局) 

sed -i '/server/s/serername/servername:/g' awk.text    先找到那一行的关键词,然后再修改

sed -i '/^SELINUX/s/enforcing/disabled/g' /etc/sysconfig/selinux    修改selinux文件永久关闭,^号是以什么为开头

sed -i '$s/server name:192.168.1.1/192.168.12/g' awk.text   $号 代表结尾,修改最后一行

sed -i ‘s/stringa1/stringa2/g’ example.txt   将example.txt文件中的 “string1” 替换成 “string2” 

sed -n ‘/stringa1/p’    查看只包含词汇 “string1”的行(grep stringa1)

sed -n ‘1,5p;5q’ example.txt    查看从第一行到第5行内容 

sed -n ‘5p;5q’ example.txt    查看第5行 

sed -i ‘/^$/d’ example.txt 从example.txt  文件中删除所有空白行 

sed -n '1p' awk.text    打印第一行 

sed -n '2p' awk.text    打印第二行

sed -i '/^#/d' example.txt|sed -i '/^$/d'   从example.txt文件中删除所有注释和空白行

df -h |sed -n '/\/$/p'|sed 's/2%/20/g'    打印磁盘分区信息

cat awk.text |sort|sed 's/ /\n/g'|sort -nr |sed -n '1p;$p' sort -nr   是从小到大的顺序排序 反之-n \n 是换行的意思

sed -n "/`(date -d "-10min" +%Y:%T)`/,/`(date +%Y:%T)`/p" /usr/local/nginx/logs/access.log 分析前十分钟的日志

sed -n ‘/2015:12:00:*/,/2015:12:30:*/’p /data/log/nginx.log|awk ‘{print $1}’|sort|uniq –c|sort –nr|head -20   打印中午12点到12点半的前20行的日志信息访问ip最多的

sed -i '/^zhang/s/$/ 11/' awk.text 匹配以zhang开头的这一行并在结尾追加内容 这里$号代表行结尾

sed -n "$=" /var/log/messages     匹配日志最后一行的行数(写监控日志关键字脚本的时候会用到)

find . -type f -exec sed -i s#/opt/csp/logs#/opt/tsp/logs#g {} +     匹配当前目录下所有的文件进行批量替换

awk:

特殊要点(内置变量):
$0           表示整个当前行
$1           每行第一个字段
$NF          字段数量变量,最后一个
$(NF-1)  字段数量变量,倒数第二个
NR          每行的记录号,多文件记录递增
FNR        与NR类似,不过多文件记录不递增,每个文件都从1开始
\t            制表符
\n           换行符
FS          BEGIN时定义分隔符
RS       输入的记录分隔符, 默认为换行符(即文本是按一行一行输入)
~            匹配,与==相比不是精确比较
!~           不匹配,不精确比较
==         等于,必须全部相等,精确比较
!=           不等于,精确比较
&&      逻辑与
||             逻辑或
+            匹配时表示1个或1个以上
/[0-9][0-9]+/   两个或两个以上数字
/[0-9][0-9]*/    一个或一个以上数字
FILENAME 文件名
OFS      输出字段分隔符, 默认也是空格,可以改为制表符等
ORS        输出的记录分隔符,默认为换行符,即处理结果也是一行一行输出到屏幕
-F'[:#/]'   定义三个分隔符

awk -F '[ !]' '{print substr($3,6)}' test.txt  substr($3,6)  表示是从第3个字段里的第6个字符开始,一直到设定的分隔符结束. substr($3,12,6)  --->  表示是从第3个字段里的第12个字符开始,截取6个字符结束.

df -h |awk '{print $1}'       打印第一竖行的数据

df -h |awk '{pring $1,$2}'   打印第二竖行的数据

df -h |awk '{print $1":"$2}'     打印数据的$1,$2之间加个:号

df -h |awk '{print $1"------>"$2}'

ifconfig eth0|grep "Bcast"|awk '{print $2}'|sed 's/addr://g'      取出eth0网卡ip

ifconfig eth0|grep "Bcast"|awk '{print $2}'|awk -F: '{print $2}'  取出eth0网卡ip

ifconfig eth0|grep "Bcast"|awk '{print $2}'|awk -F: '{print $2}'|awk -F. '{print "addr:"$1"."$2"."$3".""0"}'

df -h|awk '/\/$/ {print $0}'        匹配以/为结尾分区所有内容($ 为结尾,\  防止窜意)同grep "\/$"

awk -F ":" '{ if($NF-1>40)print $2}' localhost_access_log.2022-01-10.txt|uniq -c

(1) 取出/分区使用大小

df -h|awk '/\/$/ {print $0}'|sed 's/%//g'|awk '{print $5}' 

(2) 监控判断磁盘大小 

df -h|awk '/\/$/ {print $0}'|sed 's/%//g'|awk '{if($5>80)print "ture";else print "fales"}'      

df -h|awk '/\/$/ {print $0}'|sed 's/%//g'|awk '{if($5>80){print "ture"}else{print "fales"}}'    

(3) 搜索这条数据加起来有多少,再进行判断

cat tsc-xcall.log|grep "send msd to tmp ok"|awk '{a+=1}END{if(a>10)print "t";else print "f"}'

(4) 统计Nginx服务器总PV量。

awk  '{print $7}' access.log |wc -l     

(5) 统计Nginx服务器UV统计。

awk  '{print $11}' access.log |sort -r|uniq -c |wc -l     

(6) 打印这段时间内有多少条200的数据记录

cat /usr/local/nginx/logs/access.log|sed -n "/2016:09:00:00/,/2016:10:00:00/"p|grep "200"|awk '{print $10}'|awk '{sum += $1} END {print sum}'     
cat /usr/local/nginx/logs/access.log|sed -n "/2016:09:00:00/,/2016:10:00:00/"p|awk '{print $NF}' |sed 's/"/" /'g|awk '{print $2}'|sed 's/"/ "/'g|awk '{if ($1>3)print $1}'|wc -l

awk  '/2017:09:00/,/2017:12:00/' access.log|wc –l

(7) 分析截止目前为止访问量最高的IP排行并且访问量超过100的ip。

awk '{print $1}' /usr/local/nginx/logs/access.log|sort |uniq -c |sort -nr |awk ‘{if($1>=100) print $0}’|head -10     

(8) 分析前十分钟的日志 

sed -n "/`(date -d "-10min" +%Y:%T)`/,/`(date +%Y:%T)`/p" /usr/local/nginx/logs/access.log                   

access.log|awk ‘{print $1,$7}’|sort|uniq –c |sort –nr

(9) 查找访问请求超过0.5秒的url

awk ‘{if ($NF>0.5) print $1,$7,$NF}’ access.log|more      

(10) 找到当前日志中502或者404错误的页面并统计。

awk‘{if(($9=502)||($9=404)) print $1,$7,$9 }’ /usr/local/nginx/logs/access.log|sort|uniq –c|sort -nr    

(11) 分析Nginx访问日志状态码404、502、503、500、499等错误信息页面,打印错误出现次数大于20的IP地址。

awk‘{if($9~/502|499|500|503|404/) print $1,$7,$9 }’/usr/local/nginx/logs/access.log|sort|uniq –c|sort -nr |awk '{if($1>20) print $2}'   

(12) 找到当前日志中502或者404错误的页面并统计。 

awk '{print $0}' /usr/local/nginx/logs/access.log|egrep "404|502"|awk '{print $1,$7,$9}'|more  

(13) 统计netstat -anp 状态为CONNECT的连接数量是多少 

netstat -anlp|grep java|awk '/^tcp/ && /ESTABLISHED/{t++}END{print t}') 

(14) 按(小时/天)统计接口请求超过50毫秒的计数 

awk -F'[:,]' '{if ($(NF-2)>50)print substr($3,1)}' localhost_access_log.2022-01-10.txt|uniq -c|sort -nr|sort -k 2  

awk -F'latency":' '{split($2,a,",");if(a[1]>50)print a[1]}' localhost_access_log.2022-01-10.txt|wc -l  

(15) 按(天)统计接口请求超过5秒的url

cat localhost_access_log.2022-04-05.txt|awk -F"latency\":" '{split($2,a,"[,]");if(a[1]>5000)print $0}'|awk -F":" '{print $15}'|awk -F"/" '{OFS="/";$NF="";print $0}'|sort|uniq -c 

(16) 按(天)统计接口请求超过5秒的时间段

cat localhost_access_log.2022-04-05.txt|awk -F"latency\":" '{split($2,a,"[,]");if(a[1]>5000)print $0}'|awk -F"/" '{print substr ($3,0,10)}'|uniq -c|sort -nr    

 
运算符:

(1) awk 赋值运算符:a+5;等价于: a=a+5;其他同类

awk 'BEGIN{a=5;a+=5;print a}'

(2) awk正则运算符:

awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'

echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'

(3) 关系运算符:

awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出

awk 'BEGIN{a=11;if(a>=9){print "ok"}}'

awk 'BEGIN{a;if(a>=b){print "ok"}}'

 

awk 正则:

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

awk '/root/{print $0}' passwd ##匹配所有包含root的行

awk -F: '$5~/root/{print $0}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行

ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print $4}'

布尔表达式

awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。

awk -F: '$1=="root"{print $0}' passwd

awk -F: '($1=="root")&&($5=="root") {print $0}' passwd

 

数组的典型应用:

用 awk 中查看服务器连接状态并汇总 

netstat -an|awk '/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}'

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

awk '{a[$7]+=$10;++b[$7];total+=$10}END{for(x in a)print b[x],x,a[x]|"sort -rn -k1";print

 
printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。在编写程序时经常会用到此函数:
printf()函数的调用格式为: printf("", ); 
%d 十进制有符号整数 
%u 十进制无符号整数 
%f 浮点数 
%s 字符串 
%c 单个字符 
%p 指针的值 
%e 指数形式的浮点数 
%x, %X 无符号以十六进制表示的整数 
%0 无符号以八进制表示的整数 
%g 自动选择合适的表示法 
\n 换行 
\f 清屏并换页 
\r 回车 
\t Tab符 
\xhh 表示一个ASCII码用16进表示,其中hh是1到2个16进制数 
 
说明: 
(1). 可以在"%"和字母之间插进数字表示最大场宽。 
例如: %3d 表示输出3位整型数, 不够3位右对齐。 
%9.2f 表示输出场宽为9的浮点数, 其中小数位为2, 整数位为6,小数点占一位, 不够9位右对齐。 
%8s 表示输出8个字符的字符串, 不够8个字符右对齐。 
如果字符串的长度、或整型数位数超过说明的场宽, 将按其实际长度输出.但对浮点数, 若整数部分位数超过了说明的整数位宽度, 将按实际整数位输出;若小数部分位数超过了说明的小数位宽度, 则按说明的宽度以四舍五入输出.
另外, 若想在输出值前加一些0, 就应在场宽项前加个0。 
例如: %04d 表示在输出一个小于4位的数值时, 将在前面补0使其总宽度为4位。 
如果用浮点数表示字符或整型量的输出格式, 小数点后的数字代表最大宽度,小数点前的数字代表最小宽度。 
例如: %6.9s 表示显示一个长度不小于6且不大于9的字符串。若大于9, 则第9个字符以后的内容将被删除。
 
例子:
$ echo "1.7 2.52" | awk '{printf ("%d\n",$2)}'  #整数换行输出第2个域
2
$ echo 1 2|awk '{printf("%0.2f\n",$1/$2)}'          #输出运算结果两位浮点数
0.50
$ echo "1.7 2.52" | awk '{printf ("%f\n",$1)}'  #浮点换行输出第1个域
1.700000
$ echo "1.5" | awk '{printf ("%.f\n",$1)}'     #四舍五入输入整数
2
 
$ echo "1.7 2.52" | awk '{printf ("%3.1f\n",$2)}'  #以3位长度、1位小数,"."占一位,浮点换行输出第2个域(四舍五入)。
2.5
 
$ echo "1.7 2.52" | awk '{printf ("%6.3f\n",$2)}'  #以6位长度,其中整数占2位,不足2位空格补足,“.”占一位,小数占3位,不足3位用0补足。
 2.520
 
$ echo "1.7 2.52" | awk '{printf ("%e\n",$1)}'  #指数形式的浮点数输出。
1.700000e+00
 
$ echo "123 1" | awk '{printf("%d\t%03d\n",$1,$2)}'  #用0补充格式
123     001

 awk 内置函数:

split 初始化和类型强制 
awk的内建函数split允许你把一个字符串分隔为单词并存储在数组中。你可以自己定义域分隔符或者使用现在FS(域分隔符)的值。
格式:

   split (string, array, field separator)
   split (string, array)  -->如果第三个参数没有提供,awk就默认使用当前FS值。

例子:
例1:替换分隔符

time="12:34:56"
echo $time | awk '{split($0,a,":");print a[1],a[2],a[3]}'

例2:split可以实现对字符串进行数组类型的分割。

echo ‘abcd’ | awk ‘{len=split($0,a,””);for(i=1;i<=len;i++)print “a[“i”]=”a[i];print “length=”len}’

a[1]=a

a[2]=b

a[3]=c

a[4]=d

length=4

解析说明:首先把abcd换为一个数组,并且数组的分隔符为没有符号,len=split($0,a,””)为获取了整个数组的长度,之后进行输出。在awk中如果是当做字符串输出的字符,全部用双引号来引起来。

substr 截取字符串

返回从起始位置起,指定长度之子字符串;若未指定长度,则返回从起始位置到字符串末尾的子字符串。
格式:
  substr(s,p) 返回字符串s中从p开始的后缀部分
  substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分
例子:

echo "123" | awk '{print substr($0,1,1)}'

1

解释:

awk -F ',' '{print substr($3,6)}'    --->  表示是从第3个字段里的第6个字符开始,一直到设定的分隔符","结束.
substr($3,10,8)  --->  表示是从第3个字段里的第10个字符开始,截取8个字符结束.
substr($3,6)     --->  表示是从第3个字段里的第6个字符开始,一直到结尾

length 字符串长度
length函数返回没有参数的字符串的长度。length函数返回整个记录中的字符数。

echo "123" | awk '{print length}'

3

gsub函数

gsub函数则使得在所有正则表达式被匹配的时候都发生替换。gsub(regular expression, subsitution string, target string);简称 gsub(r,s,t)。

举例:把一个文件里面所有包含 abc 的行里面的 abc 替换成 def,然后输出第一列和第三列

awk '$0 ~ /abc/ {gsub("abc", "def", $0); print $1, $3}' abc.txt

 

替换:

awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}' this is a test!test!info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未
给 info 值,默认是$0

查找 

awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'
ok #未找到,返回 0

匹配查找 

awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'
ok #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

截取 

awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'
s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

分割 

awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4
4 test 1 this 2 is 3 a
#分割 info,动态创建数组 tA,awk forin 循环,是一个无序的循环。 并不是从数组下标
1…n 开始

 

cut:

-d   以什么为分隔符

-f    打印

cat /etc/passwd | cut -d : -f 1   #以:分割,取第一段

a=daemon:x:2:2:daemon:/sbin:/sbin/nologin

echo $a | cut -d: -f 1

daemon

在linux中字符串的截取我们可以用一个命令叫做cut,cut主要截取方法有三种

1)字节(bytes),用选项-b ,使用方法cut -b/c/f 
2)字符(characters),用选项-c 
3)域(fields),用选项-f

 

Shell中的${}、##和%%使用范例:
假设定义了一个变量为: 
代码如下: 
file=/dir1/dir2/dir3/my.file.txt 
可以用${ }分别替换得到不同的值: 
${file#*/}:删掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt 
${file##*/}:删掉最后一个 / 及其左边的字符串:my.file.txt 
${file#*.}:删掉第一个 . 及其左边的字符串:file.txt 
${file##*.}:删掉最后一个 . 及其左边的字符串:txt 
${file%/*}:删掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3 
${file%%/*}:删掉第一个 / 及其右边的字符串:(空值) 
${file%.*}:删掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file 
${file%%.*}:删掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my 

posted on 2019-05-27 16:02  走路带风的帅界扛把子  阅读(357)  评论(0编辑  收藏  举报