2018-07-26 第三十一次课
第三十一次课 shell编程(一)
目录
一、shell脚本介绍
二、shell脚本结构和执行
三、date命令用法
四、shell脚本中的变量
五、hell脚本中的逻辑判断
六、文件目录属性判断
七、if特殊用法
八、case判断
九、for循环
十、while循环
十一、break跳出循环
十二、continue结束本次循环
十三、exit退出整个脚本
十四、扩展
一、shell脚本介绍
shell是一种脚本语言, 是用户与内核进行交互的一种接口。
shell可以使用逻辑判断、循环等语法,也可以自定义函数。
shell是系统命令的集合
shell脚本可以实现自动化运维,能大大增加我们的运维效率
二、shell脚本结构和执行
shell脚本通常在编辑器中编写,由命令及其注释组成,注释是跟在#号后的内容,用来对脚本进行解释。
第一行 位于脚本左上角的第一行会指出由哪个程序来执行脚本中的行。这一行通常称为shbang,写作#!/bin/bash
一个bash shell程序由一组unix/linux命令、bash命令、程序结构控制语句和注释组成
为便于区分,一般以.sh结尾。
例如:
#!/bin/bash
# Scriptname: greet
for name in $* # same as for name in $@
do
echo Hi $name
done
shell的执行方式有二种
- chmod u+x greet.sh; ./sh 或绝绝对路径执行
- bash greet.sh
//执行方式1
[root@localhost sh]# vim greet.sh
[root@localhost sh]# chmod u+x greet.sh
[root@localhost sh]# ./greet.sh kennminn
Hi kennminn
或者
[root@localhost sh]# chmod u+x greet.sh
[root@localhost sh]# pwd
/root/script/sh
[root@localhost sh]# /root/script/sh/greet.sh kennminn
Hi kennminn
//执行方式2
[root@localhost sh]# bash greet.sh kennminn
Hi kennminn
查看脚本的执行过程 bash -x script-name
[root@localhost sh]# bash -x greet.sh kennminn
+ for name in '$*'
+ echo Hi kennminn
Hi kennminn
查看脚本是否有语法错误
//没有语法错误时
[root@localhost sh]# bash -n greet.sh kennminn
//将最后一行的done删掉
[root@localhost sh]# vim greet.sh
#!/bin/bash
# Scriptname: greet
for name in $* # same as for name in $@
do
echo Hi $name
[root@localhost sh]# bash -n greet.sh kennminn
greet.sh: line 7: syntax error: unexpected end of file
三、date命令用法
date命令打印系统日期和时间。
[root@localhost sh]# date
Sun Jul 29 21:08:24 EDT 2018
常用格式
命令 | 含义 |
---|---|
date +%Y | 年(4位) |
date +%y | 年(2位) |
date +%m | 月 |
date +%d | 日 |
date +%D | 以月/日/年格式显示日期 |
date +%F | 以年-月-日格式显示日期 |
date +%H | 小时 |
date +%M | 分钟 |
date +%S | 秒 |
date +%T | 以时:分:秒格式显示时间,等于date +%H:%M:%S |
date +%s | 时间戳表示距离1970年1月1日到现的秒数 |
date +%w | 这个星期的第几周 |
date +%W | 今年的第几周 |
date +%h | 月份缩写,等于date +%b |
date -d "-1 day" | 一天前 |
date -d "+1 day" | 一天后 |
date -d "-1 year" | 一年前 |
date -d "-1 month" | 一个月前 |
date -d "-1 hour" | 一小时前 |
date -d "-1 min" | 一分钟前 |
eg:
//显示日期
[root@localhost sh]# date +%Y-%m-%d
2018-07-29
[root@localhost sh]# date +%F
2018-07-29
[root@localhost sh]# date +%D
07/29/18
//显示时间
[root@localhost sh]# date +%H:%M:%S
09:22:23
[root@localhost sh]# date +%T
09:22:30
//显示时间戳
[root@localhost sh]# date +%s
1532913790
//显示1天后的日期
[root@localhost sh]# date -d "+1 day"
Tue Jul 31 09:24:16 CST 2018
//显示1天前的日期
[root@localhost sh]# date -d "-1 day"
Sun Jul 29 09:24:43 CST 2018
//显示1小时前的时间
[root@localhost sh]# date -d "-1 hour" +%T
08:25:43
//将时间戳以日期格式显示
[root@localhost sh]# date -d @1532913790
Mon Jul 30 09:23:10 CST 2018
//显示指定日期的时间戳
[root@localhost sh]# date +%s -d "2018-06-23"
1529683200
//显示日历
[root@localhost sh]# cal
July 2018
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
//显示指定月的日历
[root@localhost sh]# cal 7 17
July 17
Su Mo Tu We Th Fr Sa
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
四、shell脚本中的变量
变量就是为某个信息片段所起的名字,标志内存中的一段地址。
当脚本中使用某个字符串较频繁并且字符串长度很长时就应该使用变量代替
使用条件语句时,常使用变量 if [ $a -gt 1 ]; then ... ; fi
引用某个命令的结果时,用变量替代 n=wc -l 1.txt
或者n=$(wc -l 1.txt)
写和用户交互的脚本时,变量也是必不可少的 read -p "Input a number: " n; echo $n 如果没有指定变量名n,默认变量名为REPLY
内置变量 $0, $1, $2… $0表示脚本本身,$1 第一个参数,$2 第二个 .... $#表示参数个数,
$*表示获取当前shell脚本所有传参的个数,不加引号和$@相同,加上引号则将所有的参数视为单个字符串。相当于”$1 $2 $3”。
$@表示获取当前shell脚本所有传参的参数,不加引号和$*相同。如果给$@加上双引号,例如”$@”,则表示将所有的参数视为不同的独立字符串,相当于”$1”,”$2”,”$3”….这是将多参数传递给其他程序的最佳方式,因为它会保留所有的内嵌在每个参数里的任何空白。当”$@”和”$*”都加双引号时,两者是有区别的,都不加双引号,两者无区别。
变量有环境变量和用户自定义变量
用户自定义变量变量名可以由一个字母、数字或下划线符号组成,不能以数字开头。长度不超过20个字符。变量名区分大小写,请留意:Var1 和var1不是同一个变量。
例如:
//等号(=)两端不能有空格
//引用变量值的方式:在变量名前加$
[root@localhost sh]# name=terry
[root@localhost sh]# echo $name
terry
[root@localhost sh]# name =terry
-bash: name: command not found
shell中只能进行整数运行,如果需要进行浮点数,需要借助bc命令
整数运算语法
1.$[ ]
[root@localhost sh]# n=5;echo $[$n+1]
6
2.$(())
[root@localhost sh]# n=5;echo $(($n+1))
6
[root@localhost sh]# n=5;echo $((n+1))
6
3.(())
[root@localhost sh]# ((n+=1));echo $n
6
4.expr
//注意+号两边要有空格
[root@localhost sh]# expr 4 + 5
9
[root@localhost sh]# r=`expr 4 + 5`
[root@localhost sh]# echo $r
9
5.let
[root@localhost sh]# let n=n+1
[root@localhost sh]# echo $n
1
五、hell脚本中的逻辑判断
格式1:if 条件 ; then 语句; fi
[root@localhost sh]# vim if1.sh
#!/bin/bash
a=3
if [ $a -gt 2 ]
then
echo ok!
fi
[root@localhost sh]# chmod u+x if1.sh
[root@localhost sh]# ./if1.sh
ok!
或者
[root@localhost sh]# a=3;if [ $a -gt 2 ]; then echo ok! ; fi
ok!
格式2:if 条件; then 语句; else 语句; fi
[root@localhost sh]# vim if2.sh
#!/bin/bash
a=1
if [ $a -gt 2 ]
then
echo ok!
else
echo It\'s no ok!
fi
[root@localhost sh]# ./if2.sh
It's no ok!
[root@localhost sh]# sh -x ./if2.sh
+ a=1
+ '[' 1 -gt 2 ']'
+ echo 'It'\''s' no 'ok!'
It's no ok!
格式3:if …; then … ;elif …; then …; else …; fi
[root@localhost sh]# vim if3.sh
#/bin/bash
a=2
if [ $a -eq 3 ];then
echo The number is three.
elif [ $a -gt 3 ];then
echo the number is great then three.
else
echo the number is less then three.
fi
[root@localhost sh]# chmod u+x if3.sh
[root@localhost sh]# ./if3.sh
the number is less then three.
[root@localhost sh]# sh -x ./if3.sh
+ a=2
+ '[' 2 -eq 3 ']'
+ '[' 2 -gt 3 ']'
+ echo the number is less then three.
the number is less then three.
test命令的数值比较功能
比较 | 描述 |
---|---|
n1 -eq n2 | 检查n1是否等于n2 |
n1 -ge n2 | 检查n1是否大于等于n2 |
n1 -gt n2 | 检查n1是否大于n2 |
n1 -le n2 | 检查n1是否小于等于n2 |
n1 -lt n2 | 检查n1是否小于n2 |
n1 -ne n2 | 检查n1是否不等于n2 |
test命令的字符串比较
比较 | 描述 |
---|---|
str1 = str2 | 检查str1和str2是否相等 |
str1 != str2 | 检查str1和str2是否不相等 |
str1 < str2 | 检查str1是否比str2小 |
str1 > str2 | 检查str1是否比str2大 |
可以使用 && ||结合多个条件
if [ $a -gt 5 ] && [ $a -lt 10 ] &&表示并且
if [ $b -gt 5 ] || [ $b -lt 3 ] ||表示或者
六、文件目录属性判断
文件比较
比较 | 描述 |
---|---|
-d file | 检查文件是否存且是一个目录 |
-e file | 检查文件是否存在 |
-f file | 检查文件是否存且是一个文件 |
-r file | 检查文件是否存在且可读 |
-s file | 检查文件是否存在且非空 |
-w file | 检查文件是否存在并可写 |
-x file | 检查文件是否存在并可执行 |
-o file | 检查文件是否存在并属当前用户所有 |
-G file | 检查文件是否存在并且默认组与当前用户相同 |
file1 -nt file2 | 检查file1是否比file2新 |
file1 -ot file2 | 检查file1是否比file2旧 |
[root@localhost sh]# vim file1.sh
#/bin/bash
f1='/tmp/tt.txt'
if [ -f $f1 ];then
echo "$f exist"
else
touch $f1
fi
//第一次文件不存在时
[root@localhost sh]# sh -x file1.sh
+ f1=/tmp/tt.txt
+ '[' -f /tmp/tt.txt ']'
+ touch /tmp/tt.txt
//第二次文件已经存在
[root@localhost sh]# sh -x file1.sh
+ f1=/tmp/tt.txt
+ '[' -f /tmp/tt.txt ']'
+ echo ' exist'
exist
//判断文件目录是否存在
[root@localhost sh]# cp file1.sh file2.sh
[root@localhost sh]# vim file2.sh
#/bin/bash
f1='/tmp/tt.txt'
if [ -f $f1 ];then
echo "$f exist"
fi
[root@localhost sh]# ./file2.sh
exist
//判断文件是否可读
[root@localhost sh]# cp file2.sh file3.sh
[root@localhost sh]# vim file3.sh
#/bin/bash
f1='/tmp/tt.txt'
if [ -r $f1 ];then
echo "$f is readable"
fi
[root@localhost sh]# ./file3.sh
is readable
七、if特殊用法
比较 | 描述 |
---|---|
-n str2 | 检查str1的长度是否非0 |
-z str2 | 检查str1的长度是否为0 |
[root@localhost sh]# vim file4.sh
#!/bin/bash
file='/tmp/tt.txt'
if [ -n "$file" ];then
echo "the file $file is not empty"
fi
[root@localhost sh]# ./file4.sh
the file /tmp/tt.txt is empty
其他特殊用法
使用命令来做判断条件
//-q表示静默模式
//grep命令匹配其返回值是0,如果没有匹配则返回值是非0
[root@localhost sh]# if grep -q 'hjm' /etc/passwd;then echo user exist;fi
user exist
使用! 在参数前 表示取反 [ ! -e file ] 表示文件不存在
中括号中不能使用<,>,==,!=,>=,<=这样的符号
八、case判断
语法:
case 变量名 in
value1)
command
;;
value2)
command
;;
*)
commond
;;
esac
在case程序中,可以在条件中使用|,表示或的意思, 比如
a|b)
command
;;
eg
[root@kun05 shell]# vim case1.sh
#!/bin/bash
read -p "Please input number: " n
#让用户输入数字
if [ -z "$n" ]
then
echo "Please input number: "
exit 1
fi
#判断用户是否没填数字
n1=`echo $n|sed 's/[0-9]//g'`
if [ ! -z "$n1" ]
then
echo "Please input number: "
exit 1
fi
#判断用户是否填纯数字
if [ $n -lt 60 ]
then
tag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ]
then
tag=2
elif [ $n -ge 80 ] && [ $n -lt 90 ]
then
tag=3
elif [ $n -ge 90 ] && [ $n -le 100 ]
then
tag=4
else
tag=0
fi
#给分数赋值给tag
case $tag in
1)
echo "bu ji he"
;;
2)
echo "liang hao"
;;
3)
echo "you xiu"
;;
4)
echo "fei chang bang"
;;
*)
echo "The number range is 0-100"
;;
esac
[root@localhost sh]# vim grade.sh
[root@localhost sh]# sh -x ./grade.sh
+ read -p 'Please input number: ' n
Please input number: 60
+ '[' -z 60 ']'
++ echo 60
++ sed 's/[0-9]//g'
+ n1=
+ '[' '!' -z '' ']'
+ '[' 60 -lt 60 ']'
+ '[' 60 -ge 60 ']'
+ '[' 60 -lt 80 ']'
+ tag=2
+ case $tag in
+ echo 'liang hao'
liang hao
九、for循环
语法格式
for 变量名 in 条件; do …; done
eg
//计算1到100的和
[root@localhost sh]# vim sum.sh
#!/bin/bash
result=0
for i in $(seq 1 100)
do
result=$((result+i))
done
echo $result
[root@localhost sh]# chmod u+x sum.sh
[root@localhost sh]# ./sum.sh
5050
//遍历/etc目录并把目录列出来
[root@localhost sh]# vim for2.sh
#!/bin/bash
cd /etc
for file in *
do
[ -d $file ] && ls $file
done
[root@localhost sh]# chmod u+x for2.sh
[root@localhost sh]# ./for2.sh | more
abrt-action-save-package-data.conf
abrt.conf
gpg_keys.conf
plugins
ld
libnssckbi.so.x86_64
mta
mta-aliasesman
...下略
十、while循环
语法格式
while 条件; do … ; done
eg
//每隔30秒查看系统负载,当大于10时发邮件
[root@localhost sh]# vim while1.sh
#!/bin/bash
while :
do
load=`w|head -1|awk -F 'load average: ' '{print $2}'|cut -d . -f1`
if [ $load -gt 10 ]
then
/usr/local/sbin/mail.py coco44566@163.com "load high" "$load"
fi
sleep 30
done
[root@localhost sh]# chmod u+x while1.sh
[root@localhost sh]# sh -x while1.sh
+ :
++ w
++ cut -d . -f1
++ awk -F 'load average: ' '{print $2}'
++ head -1
+ load=0
+ '[' 0 -gt 10 ']'
+ sleep 30
: ture 1 都是代表为正 因此while : 就是一个死循环
为了不让while脚本不意外终止 可以使用screen命令 再到screen下执行此脚本
//提示让用户只能输入数字
[root@localhost sh]# vim while2.sh
#!/bin/bash
while :
do
read -p "Please input a number: " n
if [ -z "$n" ]
then
echo "Please input sth!"
continue
fi
##判断用户是否直接回车
n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
then
echo "Please input number!"
continue
fi
#判断用户是否输入纯数字
echo $n
break
done
[root@localhost sh]# sh while2.sh
Please input a number: a
Please input number!
Please input a number: v
Please input number!
Please input a number: 1
1
echo $n|sed 's/[0-9]//g 把数字替换为空,再来判断剩下的内容
十一、break跳出循环
eg
[root@kun05 shell]# vim break.sh
#!/bin/bash
for i in $(seq 1 5)
do
echo $i
if [ $i -eq 3 ]
then
break
fi
echo $i
done
echo aaaa
[root@localhost sh]# chmod u+x break.sh
[root@localhost sh]# ./break.sh
[root@localhost sh]# ./break.sh
1
1
2
2
3
aaaa
十二、continue结束本次循环
忽略本次循环,直接进行下一次循环
eg
[root@localhost sh]# mv break.sh continue.sh
[root@localhost sh]# vim continue.sh
#!/bin/bash
for i in $(seq 1 5)
do
echo $i
if [ $i -eq 3 ]
then
continue
fi
echo $i
done
echo aaaa
[root@localhost sh]# ./continue.sh
1
1
2
2
3
4
4
5
5
aaaa
十三、exit退出整个脚本
eg
[root@localhost sh]# mv continue.sh exit.sh
[root@localhost sh]# vim exit.sh
#!/bin/bash
for i in $(seq 1 5)
do
echo $i
if [ $i -eq 3 ]
then
exit 1
fi
echo $i
done
echo aaaa
[root@localhost sh]# ./exit.sh
1
1
2
2
3
总结:
break,continue都是在for while循环中使用的
break出现时候会跳出本次循环 直接忽略掉了break后面的代码
continue出现时候也会忽略掉了continue后面的代码并重新再来执行循环
exit直接跳出脚本 一般exit 后面会跟一个数字 给用户返回该值
十四、扩展
select用法