一、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结尾。
1. Shell脚本内容的第一行需要加:#!/bin/bash
意思是指定命令解释器,由什么解释器来执行这个脚本。例如:
[root@Linux01 ~]# cat 1.sh
#!/bin/bash
echo 123
w
ls
2. 以#开头的行作为解释说明,解释器不会去执行它。
3. 脚本的文件名通常以 .sh 结尾,用于区分这个文件是一个 shell 脚本。
4. 执行方法有两种:
①一种方法是使用 bash 或者 sh 命令 来执行指定的脚本
[root@Linux01 ~]# bash 1.sh
或[root@Linux01 ~]# sh 1.sh
②另一种方法是使用相对路径或者绝对路径去执行,脚本执行前需要给脚本加上可执行权限
5. 查看脚本执行过程
[root@Linux01 ~]# sh -x 1.sh
6. 查看脚本是否有语法错误(只能查看语法问题,命令有错误不检查)
[root@Linux01 ~]# bash -n 1.sh
没有错误不输出;有错误就会输出错误位置。
三、date命令用法
date命令用于设置或者显示日期。
默认为显示系统当前时间:
[root@Linux01 ~]# date
2019年 01月 12日 星期六 22:37:35 CST
# 固定格式: date "+"
# + 后面跟指定的时间变量
# 常用的时间变量如下:
输出指定时间,要加-d选项
命令 | 含义 |
---|---|
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" | 一分钟前 |
①时间戳与日期相互转换:
[root@Linux01 ~]# date +%s
1547305554
[root@Linux01 ~]# date -d @1547305554
2019年 01月 12日 星期六 23:05:54 CST
②把指定时间转换为时间戳,并转回日期格式
[root@Linux01 ~]# date +%s -d "2019-01-12 23:05:54"
1547305554
[root@Linux01 ~]# date -d @1547305554
2019年 01月 12日 星期六 23:05:54 CST
③显示日历
[root@Linux01 ~]# cal
一月 2019
日 一 二 三 四 五 六
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脚本中的变量
变量的定义方式:
一般的变量定义方式: 变量名=值 等号两边不能有空格
调用变量的方式: $变量名 ,如果变量名后面还有字符最好加上{} 比如 ${a}bc
例:
[root@Linux01 ~]# vim 11.sh
#!/bin/bash
c=123
count=10
echo $c
echo $count
echo ${c}ount
[root@Linux01 ~]# sh 11.sh
123
10
123ount
哪些情况会使用到变量:
• 当脚本中使用某个字符串较频繁并且字符串长度很长时就应该使用变量代替
• 使用条件语句时,常使用变量 if [ $a -gt 1 ]; then ... ; fi
• 引用某个命令的结果时,用变量替代 n=`wc -l 1.txt`
• 写和用户交互的脚本时,变量也是必不可少的 read -p "Input a number: " n; echo $n 如果没写这个n,可以直接使用$REPLY
• 内置变量 $0, $1, $2… $0表示脚本本身,$1 第一个参数,$2 第二个 .... $#表示参数个数
• 数学运算a=1;b=2; c=$(($a+$b))或者$[$a+$b]
变量有环境变量和用户自定义变量。
用户自定义变量变量名可以由一个字母、数字或下划线符号组成,不能以数字开头。长度不超过20个字符。变量名区分大小写,请留意:Var1 和var1不是同一个变量。
shell中只能进行整数运行,如果需要进行浮点数,需要借助bc命令。
# 算术运算符
+、-、*、/、%、** # 加、减、乘、除、取余
++、-- # 自增,自减 ,用法$[++a] 或者 $[a++],++前置表示先运算再输出,++后置表示先输出再运算
# 比较运算符
<、<=、==、>=、>、!= # 小于、小于等于、相等与、大于等于、大于、不等于
# 逻辑运算符
!:取反 &&:逻辑与 ||:逻辑或 ~:按位取反 |:按位异或 &:按位与 ^:按位或
# 赋值运算符
=、+=、-=、*=、/=、%= # a=1 、a+=1相当于a=a+1,其他的运算符类似
五、shell脚本中的逻辑判断
•格式1:if 条件 ; then 语句; fi
• 格式2:if 条件; then 语句1; else 语句2; fi //条件为真执行语句1,不为真就执行语句2
• 格式3:if 条件1; then 语句1 ;elif 条件2; then 语句2; else 语句; fi
//如果条件1为真,执行语句1; 如果条件1不为真,执行判断条件2 ,条件2为真就执行语句2; 条件1和条件2都不为真,则执行else语句。可以有N个 elif 条件。条件只要有一个为真就为真,不再往下执行
• 逻辑判断表达式:if [ $a -gt $b ]; if [ $a -lt 5 ]; if [ $b -eq 10 ]等
特殊运算符:-gt (>); -lt(<); -ge(>=); -le(<=);-eq(==); -ne(!=)
注意:条件需要使用方括号 [] 或者 双括号(()) 括起来 。 当使用方括号时,符号、变量两边必须有空格,需要用特殊的判断语法,不能使用比较运算符;双括号可以使用比较运算符,不能使用特殊判断语法。
可以使用 && || 结合多个条件:
• if [ $a -gt 5 ] && [ $a -lt 10 ]; then //[ 条件1 ] || [ 条件2 ] 条件1 和 条件2 全为真,才执行语句
• if [ $b -gt 5 ] || [ $b -lt 3 ]; then //[ 条件1 ] || [ 条件2 ] 条件1 和 条件2 只要有一个为真就为真
六、文件目录属性判断
比较 | 描述 |
---|---|
-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@Linux01 ~]# if [ -f ./11.sh ];then echo 'YES';fi //判断是否是普通文件,且存在
YES
[root@Linux01 ~]# if [ -d ./11.sh ];then echo 'YES';fi //是一个文件,不是目录,所以没有输出
[root@Linux01 ~]# if [ -e ./11.sh ];then echo 'YES';fi
YES
[root@Linux01 ~]# if [ -r ./11.sh ];then echo 'YES';fi
YES
[root@Linux01 ~]# if [ -w ./11.sh ];then echo 'YES';fi
YES
[root@Linux01 ~]# if [ -x ./11.sh ];then echo 'YES';fi
[root@Linux01 ~]# ll 11.sh
-rw-r--r-- 1 root root 81 1月 13 00:04 11.sh //不可执行,因为没有加x权限,不能使用相对路径执行
[root@Linux01 ~]# if [ -G ./11.sh ];then echo 'YES';fi
YES
[root@Linux01 ~]# if [ -O ./11.sh ];then echo 'YES';fi
YES
[root@Linux01 ~]# if [ ./11.sh -nt ./1.sh ];then echo 'YES';fi
YES
[root@Linux01 ~]# if [ ./11.sh -ot ./1.sh ];then echo 'YES';fi //11.sh比1.sh新,所以没有输出
七、if特殊用法
if [ -z "$a" ] 判断变量a是否为空,变量为空时表达式为真
if [ -n "$a" ] 表示当变量a的值不为空,不为空时表达式为真
if grep -q '123' 1.txt; 判断文件中是否包含指定的字符串,有包含为真(使用命令作为判断条件)
if [ ! -e file ]; 判断文件或目录是否存在, 不存在为真。使用! 在参数前 表示取反
[root@Linux01 ~]# echo $b
[root@Linux01 ~]# if [ -z "$b" ];then echo ok;fi //变量值为空,所以表达式为真
ok
[root@Linux01 ~]# if [ -n "$b" ];then echo ok;fi
[root@Linux01 ~]# if [ -n "$b" ];then echo ok;else echo error;fi
error
[root@Linux01 ~]# echo 'abc' > 1.txt
[root@Linux01 ~]# if grep 'd' 1.txt ;then echo YES;else echo "NO"; fi //判断文件中不包含指定字符,表达式不为真
NO
[root@Linux01 ~]# if [ ! -e ./11.sh ];then echo yes;else echo no; fi //文件不存在时,表达式才为真;文件是存在的
no
注意:无论是-n还是-z,都不能作用在文件上。只能作用于变量。
八、case判断
1. 格式:
case $变量名 in
value1) # 当变量的值是value1时,执行command_1
command1
;; # ;; 两个分号表示一个条件所执行语句的结尾
value2) # 当变量的值是value2时,执行command_2
command2
;;
*) # 当变量的值不满足前面任何一个条件时,执行command_3
commond3
;;
esac
2. 在case程序中,可以在条件中使用|,表示或的意思, 比如
a|b)
command
;;
案例:配合if使用。编辑脚本
[root@Linux01 ~]# vim 11.sh
#!/bin/bash
read -p "Please input number: " n #让用户输入数字,并赋值给n
if [ -z "$n" ] #判断n是否为空,为空时表达式成立。提示用户输入数字
then
echo "Please input number!!!"
exit 1
fi
n1=`echo $n|sed 's/[0-9]//g'` #把n的值显示出来并且把数字部分替换为空,赋值给n1
if [ -n "$n1" ] #如果n1不为空,说明填写内容包含数字外的内容,提示输入数字。判断输入是否为纯数字
then
echo "Please input number" #提示输入数字
exit 1
fi
if [ $n -ge 0 ] && [ $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 "不及格"
;;
2)
echo "良好"
;;
3)
echo "优秀"
;;
4)
echo "接近完美"
;;
*)
echo "The number range is 0-100" #不在这个范围时,提示输入数字要在这个范围内
;;
esac
[root@Linux01 ~]# sh -x 11.sh #查看执行过程
+ read -p 'Please input number: ' n
Please input number: 10
+ '[' -z 10 ']'
++ echo 10
++ sed 's/[0-9]//g'
+ n1=
+ '[' -n '' ']'
+ '[' 10 -ge 0 ']'
+ '[' 10 -lt 60 ']'
+ tag=1
+ case $tag in
+ echo 不及格
不及格
九、for循环
语法格式:for 变量名 in 条件; do …; done
会默认以空格或回车作为分隔符。
案例:
1. 计算1到100的和
[root@Linux01 ~]# vim 11.sh
#/bin/bash
sum=0
for i in `seq 1 100`
do
sum=$(($sum + $i))
done
echo $sum
[root@Linux01 ~]# sh 11.sh
5050
2. 遍历/etc目录并把目录列出来
[root@Linux01 ~]# vim 11.sh
#!/bin/bash
for a in `ls /etc/`
do
cd /etc/
if [ -d $a ]
then
echo $a
fi
done
[root@Linux01 ~]# sh 11.sh
alternatives
audisp
audit
.......
十、while循环
语法格式: while 条件; do … ; done
while后跟 : ture 1 都是代表为真 因此while : 就是无限循环
案例①:每隔30秒查看系统负载,当大于10时发邮件
[root@Linux01 ~]# vim 1.sh
#!/bin/bash
while :
do
load=`w|head -1|awk -F 'load average: ' '{print $2}'|cut -d . -f1` #过滤出负载的整数位,赋值到load变量
if [ $load -gt 10 ]
then
/usr/local/sbin/mail.py 1*******[email protected] "load high" "$load"
fi
sleep 30
done
执行脚本时,直接执行不能显示,最好查看执行过程
[root@Linux01 ~]# sh -x 1.sh
+ :
++ w
++ head -1
++ cut -d . -f1
++ awk -F 'load average: ' '{print $2}'
+ load=0
+ '[' 0 -gt 10 ']'
+ sleep 30
+ : #30s后又执行了一遍
++ w
++ head -1
++ awk -F 'load average: ' '{print $2}'
++ cut -d . -f1
+ load=0
+ '[' 0 -gt 10 ']'
+ sleep 30
案例②:提示让用户只能输入数字
[root@Linux01 ~]# vim 11.sh
#!/bin/bash
while :
do
read -p "Please input a number: " n #输入内容赋值给n
if [ -z "$n" ] #判断用户输入内容是否为空。为空,提示需要输入一些内容;不为空,跳过
then
echo "Please input sth!"
continue #返回循环
fi
n1=`echo $n|sed 's/[0-9]//g'` #把输入内容中的数字替换成空
if [ -n "$n1" ] #通过查看n1是否为空来判断用户输入的是不是纯数字
then
echo "Please input number!" #不为空,说明输入的不是纯数字,提示输入纯数字
continue #返回循环
fi
break #n1为空时,说明输入的是纯数字,表达式为假,不执行,跳出循环
echo $n
done
十一、break跳出循环
break 当达到某个条件时使用break可以跳出这个循环,但是循环语句后面的语句还会继续执行
案例:
[root@Linux01 ~]# vim 11.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@Linux01 ~]# sh 11.sh
1
1
2
2
3
aaaa
可以看出,在i为1、2,不等于3时,还在进行for循环;在为3时,执行break语句,跳出for循环,不再执行i为4、5时的循环,但是会执行循环外的语句。
十二、continue结束本次循环
continue的作用是达到某个条件时,跳过本次循环,继续执行下一个循环及后面的语句
案例:
[root@Linux01 ~]# vim 11.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@Linux01 ~]# sh 11.sh
1
1
2
2
3
4
4
5
5
aaaa
十三、exit退出整个脚本
exit是达到某个条件时,退出整个脚本,后面的循环和语句都不再去执行。
案例:
[root@Linux01 ~]# vim 11.sh
#!/bin/bash
for i in $(seq 1 5)
do
echo $i
if [ $i -eq 3 ]
then
exit
fi
echo $i
done
echo aaaa
[root@Linux01 ~]# sh 11.sh
1
1
2
2
3
总结:
break,continue都是在for、 while循环中使用的
break:会跳出循环,不再进行循环语句,但会进行循环外的语句;
continue:结束本次循环,继续后面的循环和循环外的语句;
exit:直接跳出脚本,后面的循环和循环外的语句都不再执行。 一般exit 后面会跟一个数字,给用户返回该值,执行脚本后使用echo $?查看
十四、扩展
select用法 http://ask.apelearn.com/question/7950
selet 变量名 in 命令1 命令2 命令3
do
case $变量名 in
1)
语句1
;;
.....
*)
语句
;;
esac
done
命令的顺序 与case 的顺序对应起来.