第十二章:shell脚本
一、什么是shell脚本
把所有操作都记录到一个文档中,然后去调用文档中的命令,这个文档就是shell脚本。Shell脚本能帮助我们很方便地管理服务器,因为我们可以指定一个任务计划,定时去执行某个shell脚本以满足需求。在正式编写shell脚本之前,建议自定义的脚本都放在/usr/local/sbin/目录下:一是可以更好地管理文档;二是以后接管你工作的管理员都知道自定义脚本放在那里,方便维护。
1.shell脚本的创建和执行
编写第一个shell脚本:
[root@zl_cloud ~]# cd /usr/local/sbin/
[root@zl_cloud sbin]# cat first.sh
#! /bin/bash //表示该文件用的是bash语法
## This is my first shell script //该脚本是用来干嘛的
## Writen by ZLING 2020-03-25 //作者、时间
Date //内容
echo "Hello world!"
Shell脚本通常以.sh为后缀名。内容前最好写一个该脚本的相关注释内容,以及作者、创建日期或者版本等, 方便后续回顾查看该脚本。
下面执行一下这个脚本:
①sh命令:
- -x:查看这个脚本的执行过程。
[root@zl_cloud sbin]# sh first.sh
2020年 03月 25日 星期三 17:37:14 CST
Hello world!
[root@zl_cloud sbin]#
[root@zl_cloud sbin]# sh -x first.sh
+ date
2020年 03月 25日 星期三 17:38:08 CST
+ echo 'Hello world!'
Hello world!
[root@zl_cloud sbin]#
②./ 这个格式。(使用该方法运行shell脚本的前提是有脚本本身的执行权限):
[root@zl_cloud sbin]# ./first.sh
-bash: ./first.sh: 权限不够
[root@zl_cloud sbin]# chmod +x first.sh
[root@zl_cloud sbin]# ./first.sh
2020年 03月 25日 星期三 17:39:19 CST
Hello world!
[root@zl_cloud sbin]#
2.命令date
- date +%Y:表示以四位数字格式打印年份;
- date +%y:表示以两位数字格式打印年份;
- date +%m:表示月份;
- date +%d:表示日期;
- date +%H:表示小时;
- date +%M:表示分钟;
- date +%S:表示秒;
- date +%w:表示星期。结果显示0则表示周日。
目前:
[root@zl_cloud sbin]# date +"%Y-%m-%d %H:%M:%S"
2020-03-25 17:48:41
[root@zl_cloud sbin]#
之前:
[root@zl_cloud sbin]# date -d "-1 day" +%H
17
[root@zl_cloud sbin]# date -d "-1 hour" +%H
16
[root@zl_cloud sbin]# date -d "-1 min" +%H
17
[root@zl_cloud sbin]#
二、shell脚本中的变量
如果脚本中多次出现某一个命令或路径,而你觉得路径不对想修改一下,就得一个一个修改,或者使用批量修改替换的命令修改。这样就很麻烦,变量就是用来解决这个问题的。
格式:变量名=变量的值
下面编写第一个与变量相关的脚本:
[root@zl_cloud sbin]# vi variable.sh
#! /bin/bash
## In this script we will use variables
## Writen by ZLING 2020-03-25
d=`date +%H:%M:%S`
echo "The script begin at $d"
echo "Now we will sleep 2 seconds"
sleep 2
d1=`date +%H:%M:%S`
echo "The script end at $d1"
例子中的反引号作用是将引号中的字符串当作shell命令执行,返回命令的执行结果。d和d1在脚本中作为变量出现。
[root@zl_cloud sbin]# sh variable.sh
The script begin at 19:23:38
Now we will sleep 2 seconds
The script end at 19:23:40
[root@zl_cloud sbin]#
1.数学运算
[root@zl_cloud sbin]# vi sum.sh
#! /bin/bash
## For get the sum of two numbers.
## ZLING 2020-03-25
a=1
b=2
sum=$[$a+$b]
echo "$a+$b=$sum"
数学计算要用[ ]括起来,并且前面要加符号$。
[root@zl_cloud sbin]# sh sum.sh
1+2=3
[root@zl_cloud sbin]#
2.和用户交互
[root@zl_cloud sbin]# vi read.sh
#! /bin/bash
## Using 'read' in shell script.
## ZLING 2020-03-25
read -p "please inppute a number:" x
read -p "please inppute another number:" y
sum=$[$x+$y]
echo "The sum of the two numbers is $sum"
read命令用于和用户交互,它把用户输入的字符串作为变量值:
[root@zl_cloud sbin]# sh read.sh
please inppute a number:2 //这里输入了2
please inppute another number:10 //这里输入了10
The sum of the two numbers is 12 //得出的结果
[root@zl_cloud sbin]#
加上-x选项看看执行过程:
[root@zl_cloud sbin]# sh -x read.sh
+ read -p 'please inppute a number:' x
please inppute a number:22
+ read -p 'please inppute another number:' y
please inppute another number:13
+ sum=35
+ echo 'The sum of the two numbers is 35'
The sum of the two numbers is 35
[root@zl_cloud sbin]#
3.shell脚本预设变量
/etc/init.d/iptables restart 命令前面的/etc/init.d/iptables其实就是一个shell脚本。脚本后面为什么可以跟restart字符串呢?这就设置shell脚本的预设变量。实际上,shell脚本在执行时,后面可以跟一个或者多个参数:
[root@zl_cloud sbin]# vi option.sh
#! /bin/bash
sum=$[$1+$2]
echo "sum=$sum"
[root@zl_cloud sbin]# sh -x option.sh 1 2
+ sum=3
+ echo sum=3
sum=3
[root@zl_cloud sbin]#
注意$1和$2就是shell脚本的预设变量。$1和$2的值就是执行时分别输入的1和2,$1就是脚本的第一个参数,$2是脚本的第二个参数,以此类推。预设变量是没有限制的。
还有一个$0,代表脚本本身的名字,不妨把脚本修改一下:
[root@zl_cloud sbin]# vi option.sh
sum=$[$1+$2]
#! /bin/bash
echo "$1 $2 $0"
[root@zl_cloud sbin]# sh option.sh 1 2
1 2 option.sh
[root@zl_cloud sbin]#
三、shell脚本中的逻辑判断
1.不带else
格式:
if (判断语句);then
command
fi
示例脚本如下:
[root@zl_cloud sbin]# vi if1.sh
#! /bin/bash
read -p "Please input your score:" a
if((a<60));then
echo "You didn't pass the exam."
fi
If1.sh中 出现了((a<60))这样的形式,这是shell脚本特有的格式,只用一个小括号或者不用都会报错,所以要记住这个格式。
[root@zl_cloud sbin]# sh if1.sh
Please input your score:30
You didn't pass the exam.
[root@zl_cloud sbin]# sh if1.sh
Please input your score:90
2.带有else
格式:
if (判断语句);then
command
else
command
fi
示例脚本如下:
[root@zl_cloud sbin]# vi if2.sh
#! /bin/bash
read -p "Please input your score:" a
if((a<60));then
echo "You didn't pass the exam."
else
echo "Good! You passed the exam."
fi
[root@zl_cloud sbin]# sh if2.sh
Please input your score:90
Good! You passed the exam.
[root@zl_cloud sbin]# sh if2.sh
Please input your score:30
You didn't pass the exam.
[root@zl_cloud sbin]#
脚本if2.sh和if1.sh唯一的区别是:如果输入大于或等于60的数字会有提示。
3.带有elif
格式:
if (判断语句1);then
command
elif (判断语句2);then
command
else
command
fi
示例脚本如下:
[root@zl_cloud sbin]# vi if3.sh
#! /bin/bash
read -p "Please input your score:" a
if((a<60));then
echo "You didn't pass the exam."
elif ((a>=60)) && ((a<85));then
echo "Good! You passed the exam."
else
echo "Very good! Your score is very high!"
fi
这里的&&表示“并且”的意思,当然也可以使用||表示“或者”。
[root@zl_cloud sbin]# sh if3.sh
Please input your score:60
Good! You passed the exam.
[root@zl_cloud sbin]# sh if3.sh
Please input your score:90
Very good! Your score is very high!
[root@zl_cloud sbin]#
判断数值大小除了可以用(())形式外,还可以使用[ ]。但是不能使用大于等于符号了,要使用-lt(小于)、-gt(大于)、-le(小于或等于)、-ge(大于或等于)、-eq(等于)、-ne(不等于):
# a=10; if [$a -lt 5]; then echo ok; fi
# a=10; if [$a -gt 5]; then echo ok; fi
ok
# a=10; if [$a -ge 10]; then echo ok; fi
ok
# a=10; if [$a -eq 10]; then echo ok; fi
ok
# a=10; if [$a -ne 10]; then echo ok; fi
下面是在if语句中使用&&和||的情况:
# a=10; if [$a -lt 1] || [$a -gt 5]; then echo ok; fi
ok
# a=10; if [$a -gt 1] && [$a -le 10]; then echo ok; fi
ok
4.和文档相关的判断
- -e:判断文件或目录是否存在;
- -d:判断是不是目录以及是否存在;
- -f:判断是不是普通文件以及是否存在;
- -r:判断是否有读权限;
- -w:判断是否有写权限;
- -x:判断是否可执行。
使用if判断时具体格式:
if [-e filename];then
command
fi
示例代码如下:
# if [-d /home/]; then echo ok; fi
ok
# if [-f /home/]; then echo ok; fi
因为/home/是目录而非文件,所以并不会显示ok。其他示例如下:
# if [-f /root/test.txt]; then echo ok; fi
ok
# if [-r /root/test.txt]; then echo ok; fi
ok
# if [-w /root/test.txt]; then echo ok; fi
ok
# if [-x /root/test.txt]; then echo ok; fi
# if [-e /root/test.txt]; then echo ok; fi
5.case逻辑判断
格式:
case 变量 in
value1)
command
;;
Value2)
command
;;
Value3)
command
;;
*)
command
;;
esac
判断输入数值是奇数还是偶数的脚本:
[root@zl_cloud sbin]# vi case.sh
#! /bin/bash
read -p “Input a number:” n
a=$[$n%2]
case $a in
1)
echo “The number is odd.”
;;
0)
echo “The number is even.”
;;
*)
echo “It’s not a num!”
;;
esac
脚本中$a的值为1或0,执行结果如下:
[root@zl_cloud sbin]# sh case.sh
Input a number:100
“The number is even.”
[root@zl_cloud sbin]# sh case.sh
Input a number:101
“The number is odd.”
[root@zl_cloud sbin]#
case脚本常用于编写系统服务的启动脚本。例如/etc/init.d/network中就用到了。
四、shell脚本中的循环
1.for循环
格式:
for 变量名 in 循环的条件;do
command
` done
示例脚本:
[root@zl_cloud sbin]# vi for.sh
#! /bin/bash
for i in `seq 1 5`;do
echo $i
done
[root@zl_cloud sbin]# sh for.sh
1
2
3
4
5
[root@zl_cloud sbin]#
‘seq 1 5’
表示从1到5的一个序列。
[root@zl_cloud sbin]# vi for1.sh
#! /bin/bash
for i in 1 2 3 a b;
do echo $i;
done
[root@zl_cloud sbin]# sh for1.sh
1
2
3
a
b
[root@zl_cloud ~]#
循环的条件还可以引用系统命令的执行结果(如seq 1 5),但必须要用反引号括起来。
[root@zl_cloud sbin]# vi for2.sh
#! /bin/bash
for file in `ls`;
do echo $file;
done
[root@zl_cloud sbin]# sh for2.sh
case.sh
first.sh
for1.sh
for2.sh
for.sh
if1.sh
if2.sh
if3.sh
option.sh
read.sh
sum.sh
variable.sh
[root@zl_cloud sbin]#
2.while循环
有人常用while循环来编写死循环的脚本,用来监控某项服务。
格式:
while 条件 ; do
command
done
示例脚本如下:
[root@zl_cloud sbin]# vi while.sh
#! /bin/bash
a=5
while (($a >= 1)); do
echo $a
a=$[$a-1]
done
[root@zl_cloud sbin]# sh while.sh
5
4
3
2
1
[root@zl_cloud sbin]#
另外,可==
用一个冒号代表循环条件,这样可以做到死循环:
[root@zl_cloud sbin]# vi diewhile.sh
#! /bin/bash
while :; do
command
sleep 3
Done
[root@zl_cloud sbin]# sh diewhile.sh //我试了一下,光标就会一直闪
五、shell脚本中的函数
Shell脚本中的函数就是先把一段代码整理到一个小单元中,并给这个小单元命名,当用到这段代码时直接调用这个小单元的名字即可。有时候脚本中的某段代码总是重复使用,如果写成函数,每次用到时直接用函数名代替即可。
示例脚本如下:
[root@zl_cloud sbin]# vi func.sh
#! /bin/bash
function sum()
{
sum=$[$1+$2]
echo $sum
}
sum $1 $2
[root@zl_cloud sbin]# sh func.sh 1 2
3
[root@zl_cloud sbin]#
func.sh 中的sum()为自定义函数。在shell脚本中函数格式如下:
function 函数名()
{
command1
command2
}
需要注意的是,在shell脚本中,函数一定要写在最前面。因为函数是要被调用的,如果还没有出现就被调用,肯定会出错。
六、shell脚本中的终端和继续
1.break
break用在循环中,不管是for还是while都可以。在脚本中使用它,表示退出该层循环。之所以时层,是因为我们有时候用的嵌套循环,大循环里面还有小循环,而break只是退出那一层循环,他的上层循环不受影响。
[root@zl_cloud sbin]# vi break.sh
#! /bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
break
fi
echo $i
done
echo aaaa
[root@zl_cloud sbin]# sh break.sh
1
1
2
2
3
aaaa
[root@zl_cloud sbin]#
2.continue
continue也是用在循环中的,和break不同的是,当在shell脚本中遇到continue时,结束的不是整个循环,而是本次循环。
[root@zl_cloud sbin]# vi continue.sh
#! /bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
continue
fi
echo $i
done
echo $i
[root@zl_cloud sbin]# sh continue.sh
1
1
2
2
3
4
4
5
5
5
[root@zl_cloud sbin]#
3.exit
与前两个功能类似,但是它的作用范围更大,直接退出整个shell脚本。
[root@zl_cloud sbin]# vi exit.sh
#! /bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
exit
fi
echo $i
done
echo aaaa
[root@zl_cloud sbin]# sh exit.sh
1
1
2
2
3
[root@zl_cloud sbin]#