Linux从入门到进阶全集——【第十四集:Shell编程】
- 正则表达式(与通配符)
- 正则表达式:匹配字符串,属于包含匹配[只要包含匹配条件就行],grep,awk,sed等命令支持正则表达式
- 通配符(*,?,[]):匹配文件名,属于完全匹配[必须是完全匹配条件才行],ls,find,cp等支持通配符,而不支持正则表达式
- 所有正则表达式:详情见百度百科关于正则表达式解释:https://baike.baidu.com/item/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1700215
-
重点注意1:使用{n},{n,},{n,m}这两个正则表达式时,匹配字符串需要引号引起来,并且使用转义字符【\】将花括号【{ }】转义,例如:grep "fo\{2,\}" install.log 就能匹配install.log文件中foooo的字符串。
- 重点注意2:【*】的理解:匹配前面字符0次或者任意多次,如果任意字符串的正则例如:a*(这个表示匹配所有内容),而不是匹配包含a字符的所有字符串所在行。因为a*表示a匹配0次,也就是不包含a,所以,即便不包含a的字符行会被列出来,同时,a*还表示a匹配任意多次,也就是包含a所在字符行。所以,综合而言,它匹配所有内容,这个正则表达式实际应用上没有意义。如果要匹配包含一个a字符串的行,可以这样写:aa*,这样就能匹配所有包含一个a字符串的行。
- 重点注意3:凡是表中出现的字符都是正则表达式符号,如果需要作为字符串匹配条件,这是用转义字符【\】进行转义,例如:匹配【.】这个字符,就要使用grep \. xxx.txt 这种表达式,表示匹配包含【.】这个字符的字符行,而不是任意字符。
- 字符截取命令。
- cut字段提取【列】命令
- cut -f 2,4 xx.txt
- cut -d ":" -f 2,3 xx.txt
- 例如:cut -d " " -f 1 install.log 这个命令就能截取空格分割的第一列
- 缺陷:默认分隔符是制表符tab符,要么使用-d参数指定分隔符,而对于一些不合规则的分隔符则无法正常分割
- -d:表示以什么字符作为分割,-f表示截取哪一列。
- printf命令:格式化输出,主要在awk命令中使用
- %ns:输出字符串,n:表示输出多少个字符
- %ni:输出整数,n:表示输出多少位整数
- %m.nf:输出小数,m:表示整数位数,n:表示小数位数
- \a:输出警告音
- \b:输出退格键,backspace键
- \f:清除屏幕
- \n:换行
- \r:回车,也就是Enter键
- \t:水平输出退格键,也就是Tab键
- \v:垂直输出 退格键,也就是Tab键
- 例如:
- printf %s 1 2 3 4 5
- pirntf ‘%s\t %s\t %s\t %s\n’ $(cat printf.txt)
- printf %s 1 2 3 4 5
- awk命令
- awk的使用原因:
- 所以cut的使用具有局限性,一般截取制表符分割的字符串
- awk的功能要比cut命令强大,能实现cut的所有功能:
-
- 举例:
- df -h | cut -d " " -f 5 :表示,将df -h输出的结果按照空格(“ ”)截取第五列
-
- 原因在于分隔符用空格来分割,导致截取到了第一列和第二列中间的空格列。
- 使用awk命令
- 假如我要输出第二列和第六列:awk命令:awk '{printf $2 $6}' (注意:awk后面必须是单引号,$2 $6表示第二列和第六列),输出结果如下
- 我们可以看到输出没有格式,所以增加可是制表符和换行符:awk '{printf $2 "\t" $6 "\n"}' df.txt (注意:制表符,空格符只能使用双引号,因为单引号已被使用)
-
- awk执行原理:先读入一行,截取相应列,赋给$n变量,判断是否符合要求,然后再截取第二列,以此类推。 df -h | awk '{printf $2 "\t" $6 "\n"}' :管道符和awk的配合使用
-
- 在awk中除了使用printf外还可以使用print,printf没有打印换行符,所以需要手动打印,而print可以自动打印,这一点和有些编程语言不一样。
-
- 有这样一个用途:加入我要知道磁盘sda5使用率达到12%时就报警,这该怎么实现了:
-
- 截取使用率,输出11,这样把他赋给某个变量来流程if判断,从而实现shell编程 BEGIN命令:awk 'BEGIN{print "test!!"}{print $2 "\t" $5}' df.txt (注意所有命令都必须在一个单引号内)
- awk命令指定分隔符
- FS内置变量
- awk 'BEGIN {FS=" "}{print $2 "\t" $3}'
- 再举例:awk '{FS=":"} {print $1 "\t" $3}' /etc/passwd
-
第一行没有被处理的原因:awk执行原理是先读入第一行,然后指定分隔符,所以当读入第一行后,执行awk命令,导致第一行来不及处理,所以第一行使用默认空格来分割。
- 怎么办:使用BEGIN来强制执行awk命令 :awk 'BEGIN{FS=":"} {print $1 "\t" $3}' /etc/passwd
-
-
- 有BEGIN,就一定有END命令,用来表示:在所有命令都执行完后执行END命令
-
- 进一步应用: cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"}{print $1 "\t" $3}'
-
8. awk的关系运算法:== >= <= - FS内置变量
-
- 假如我要输出第二列和第六列:awk命令:awk '{printf $2 $6}' (注意:awk后面必须是单引号,$2 $6表示第二列和第六列),输出结果如下
- awk的使用原因:
- sed命令
- cut字段提取【列】命令
- 字符处理命令
- sort排序命令:sort /etc/password
- 不适用sort:自己查看,对比一下。
- 参数:自己尝试
- -f :忽略大小写
- -n:以数值型进行排序,默认使用的是字符串型排序
- -r:反向排序
- -t:指定分隔符,默认是制表符
- -k n[,m]:按照指定的字段范围排序,从第n字段开始,m字段结束(默认到行尾)
- sort -n -t ":" -k 3,3 /etc/password
- 统计命令wc
- 参数
- -l :只统计行数
- -w:只统计单词数
- -m:只统计字符数
- 简单使用:
- 参数
- sort排序命令:sort /etc/password
- 条件判断
- test命令:例如:test -e test.txt,使用echo $?判断上一条命令的返回结果。如果test.txt文件存在则返回非0
- 但是要注意:中括号里面要有空格[ 命令 ],命令两边有空格。
- 但是要注意:中括号里面要有空格[ 命令 ],命令两边有空格。
- 测试选项
- 举例:[ -e ./shell-test/while-util-test/while-test.sh ] && echo "yes" || echo "no"
-
举例:[ -x ./shell-test/while-util-test/while-test.sh ] && echo "yes" || echo "no"
-
举例:[ ./shell-test/ -ef ./shell-test/ ] && echo "yes" || echo "no"
-
[ 2 -eq 2 ] && echo "yes" || echo "no" [ "2" -eq "2" ] && echo "yes" || echo "no"
-
[ "字符串" == "字符串" ] && echo "yes" || echo "no"
- 举例:[ -e ./shell-test/while-util-test/while-test.sh ] && echo "yes" || echo "no"
- test命令:例如:test -e test.txt,使用echo $?判断上一条命令的返回结果。如果test.txt文件存在则返回非0
- 流程控制
- if语句
-
-
-
- 样例
-
#!/bin/bash
#统计根分区使用率
#author lirenherate=$(df -h | grep "/dev/sda5" | awk '{print $5}' | cut -d "%" -f 1)
if [ $rate -ge 10 ]
then
echo "warning!/dev/sda3 is full!!!"
fi
-
-
- case语句
-
#!/bin/bash
read -t 30 -p "please input your choice: " cho
case "$cho" in
"1")
echo "you read 1"
;;
"2")
echo "you read 2"
;;
"3")
echo "you read 3"
;;
*)
echo "error"
esac
-
- for循环
-
#!/bin/bash
for time in 1 2 3 4 5 6
do
echo "your time :" $time
done -
#!/bin/bash
cd ./
ls *.tar.gz > ls.log
#事先不知道循环次数
for i in $(cat ls.log)
do
echo "gunzip " $i
done -
#!/bin/bash
#知道循环次数s=0
for ((i=1;i<=100;i=i+1))
do
s=$(($s+$i))
#s后面 不能有空格
done
echo $s
-
- while循环
-
#!/bin/bash
i=1
s=0
while [ $i -le 100 ]
do
s=$(( $s+$i ))
i=$(( $i+1 ))
doneecho "the sum is $s"
-
- until循环
-
#!/bin/bash
i=1
s=0
#until后面有空格
until [ $i -gt 100 ]
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "the sum is $s"
-
- if语句