201-Shell脚本基础-使用变量-条件测试及选择-列表式循环
Shell
Bash Shell的使用方式
·交互式
-人工干预、智能化程度高-逐条解释执行、效率低
·非交互式
-需要提前设计、智能化难度大-批量执行、效率高
一方便在后台静悄悄地运行
什么是Shell脚本
提前设计可执行语句,用来完成特定任务的文件
-解释型程序
-顺序、批量执行
Shell脚本:可以执行的一个文件,可以实现某种功能
中文:创建用户dc Shell:useradd dc

规范Shell脚本的一般组成
#!环境声明(Sha-Bang )
#注释文本
可执行代码
[root@server0 ~]#t vim /etc/rc.local#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
.. ..
touch /var/lock/subsys/local
[ -f /etc/rc.d/rc.hostname_hack ] && source /etc/rc.d/rc.hostname_hack
.. ..
脚本的创建过程
如何写出自己的第一个Shell脚本?

编写一个批处理Shell脚本
·任务需求:依次输出以下系统信息
-红帽系统版本、内核版本、当前的主机名·转换成代码
- cat /etc/redhat-release、uname -r、hostname
[root@serverO ~]# vim /root/sysinfo
#!/bin/bash
cat /etc/redhat-releaseuname -r
hostname
脚本运行及调试
·添加执行权限,独立运行
[root@serverO ~]# chmod +x /root/sysinfo
[root@server0 ~]#/root/sysinfo
Red Hat Enterprise Linux Server release 7.0 (Maipo)3.10.0-123.el7.x86_64
serverO.example.com
·通过sh执行脚本代码
-结合-选项,可以调试脚本代码
[root@server0 ~]# sh -x /root/sysinfo
+cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.0 (Maipo)
+ uname -r
.. ..
###################################################################################
案例1:书写hello.sh脚本
[root@server0 ~]# vim /root/hello.sh
echo hello world
[root@server0 ~]# /root/hello.sh #用直接路径运行脚本
-bash: /root/hello.sh: 权限不够
[root@server0 ~]# chmod +x /root/hello.sh #赋予执行权限
[root@server0 ~]# ls -l /root/hello.sh
-rwxr-xr-x. 1 root root 17 8月 8 08:57 /root/hello.sh
[root@server0 ~]# /root/hello.sh
规范Shell脚本的一般组成
• #! 环境声明,下面所有代码由那个程序进行翻译
• # 注释文本
• 可执行代码
[root@server0 ~]# vim /root/hello.sh
#!/bin/bash #以bin下bash作为此脚本的解释器
echo hello world
[root@server0 ~]#cat /root/hello.sh #显示hello.sh脚本内容
#!/bin/bash
echo hello world
[root@server0 ~]# /root/hello.sh #可以正常运行
hello world
[root@server0 ~]# vim /root/hello.sh
#!/usr/bin/python #以/usr/bin/python 作为此脚本解释器
echo hello world
[root@server0 ~]# cat /root/hello.sh
#!/usr/bin/python
echo hello world
[root@server0 ~]# /root/hello.sh #解释器是python 运行报错,echo不是Python语言
[root@server0 ~]# vim /root/hello.sh
#!/usr/bin/python
print ‘hello world’ #改为print
[root@server0 ~]# cat /root/hello.sh
#!/usr/bin/python
print ‘hello world’
[root@server0 ~]# /root/hello.sh
hello world
案例2:书写hello.sh脚本
1)输出当前红帽系统的版本信息
2)输出当前使用的内核版本
3)输出当前系统的主机名
[root@server0 ~]# vim /root/hello.sh
#!/bin/bash
echo hello world
cat /etc/redhat-release
uname -r
hostname
ifconfig | head -2
[root@server0 ~]# /root/hello.sh
####################################################
重定向输出
>: 只收集前面命令的正确输出
2>: 只收集前面命令的错误输出
&>: 收集前面命令的正确与错误输出
]# echo 123 > /opt/1.txt
]# cat /opt/1.txt
]# cat /opt/1.txt /a
]# cat /opt/1.txt /a > /opt/nsd.txt #只收集正确信息
]# cat /opt/nsd.txt
]# cat /opt/1.txt /a 2> /opt/nsd.txt #只收集错误信息
]# cat /opt/nsd.txt
]# cat /opt/1.txt /a &> /opt/nsd.txt #收集正确与错误信息
]# cat /opt/nsd.txt
单引号 '':取消所有字符的特殊意义,原样输出
[root@server0 ~]# echo '*'
[root@server0 ~]# echo '* | >? ^& $%'
案例3:书写创建用户的脚本,并且设置密码
/dev/null:黑洞设备,专用于收集不要的输出信息
[root@server0 ~]# vim /root/user.sh
#!/bin/bash
useradd nsd04 &> /dev/null
echo 用户nsd04创建成功
echo 123 | passwd --stdin nsd04 &> /dev/null
echo 用户nsd04密码设置成功
[root@server0 ~]# chmod +x /root/user.sh
[root@server0 ~]# /root/user.sh
为了提高脚本适应多变的环境与需求,所以引入了变量
变量类似于容器:以不变的名称,存储可以变化的值,方便重复运用某一个值
变量名=存储的值
[root@server0 ~]# vim /root/user.sh
#!/bin/bash
a=nsd08
useradd $a &> /dev/null
echo 用户$a创建成功
echo 123 | passwd --stdin $a &> /dev/null
echo 用户$a密码设置成功
为了降低脚本的使用难度,以及用户的体验,所以产生交互以及提示信息
read -p '屏幕的提示信息' (#-p代表print)
1.产生交互
2.记录用户在键盘上的输入
3.将记录的所有内容,最终赋值给一个变量储存
[root@server0 ~]# vim /root/user.sh
#!/bin/bash
read -p '请输入您要创建的用户名:' a
useradd $a &> /dev/null
echo 用户$a创建成功
echo 123 | passwd --stdin $a &> /dev/null
echo 用户$a密码设置成功
####################################################
变量
定义/赋值变量
• 设置变量时的注意事项
– 等号两边不要有空格
– 变量名只能由字母/数字/下划线组成,区分大小写
– 变量名不能以数字开头,不要使用关键字和特殊字符
– 若指定的变量名已存在,相当于为此变量重新赋值

查看/引用变量
• 基本格式
– 引用变量值:$变量名
– 查看变量值:echo $变量名、echo ${变量名}
[root@server0 ~]# a=rhel
[root@server0 ~]# echo $a
rhel
[root@server0 ~]# echo $a7
[root@server0 ~]# echo ${a}7 #{}把变量a与常量7进行拼接
[root@server0 ~]# b=8
[root@server0 ~]# echo ${a}${b}
##################################################
$( )或 反撇号` `: 将命令的输出,直接作为参数,参与运行
[root@server0 ~]# date
[root@server0 ~]# date +%F #显示 年-月-日
[root@server0 ~]# cd /opt/
[root@server0 opt]# mkdir nsd-$(date +%F) #每一天在opt下创建一个不同的目录,如数据库备份
[root@server0 opt]# ls
[root@server0 opt]# mkdir $(hostname)-$(date +%F)
[root@server0 opt]# ls
[root@server0 opt]# mkdir abc-`hostname`
[root@server0 opt]# ls
##################################################
变量的种类
环境变量:变量名一般为大写字母,由系统定义并且赋值完成
USER=当前系统登陆的用户名
[root@server0 /]# echo $USER
root
[root@server0 /]# su - dc
[dc@server0 ~]$ echo $USER
dc
[dc@server0 ~]$ exit
logout
[root@server0 /]# su - dcc
[dcc@server0 ~]$ echo $USER
dcc
[dcc@server0 ~]$ exit
logout
[root@server0 /]#
###################################################
位置变量:由系统定义并且赋值完成
• 在执行脚本时提供的命令行参数
– 表示为 $n,n为序号
– $1、$2、$3、$4.. .. ${10}、${11}、.. .. #加个$后面的1、2、3等都是位置变量
[root@server0 /]# vim /root/2.sh
#!/bin/bash
cat -n $1 | head -$2
[root@server0 /]# chmod +x /root/2.sh
[root@server0 /]# /root/2.sh /etc/passwd 3
[root@server0 /]# vim /root/3.sh
#!/bin/bash
echo $1
echo $2
echo $3
[root@server0 /]# chmod +x /root/3.sh
[root@server0 /]# /root/3.sh harry tom zhangsan
[root@server0 /]# vim /root/user.sh
#!/bin/bash
#read -p '请输入您要创建的用户名:' a #开头加上#注释
useradd $1 &> /dev/null
echo 用户$1创建成功
echo 123 | passwd --stdin $1 &> /dev/null
echo 用户$1密码设置成功
[root@server0 /]# /root/user.sh harry
用户harry创建成功
用户harry密码设置成功
####################################
预定义变量:由系统定义并且赋值完成
$# 已加载的位置变量的个数,专用于用户是否输入参数(参数个数求和)
[root@server0 /]# vim /root/3.sh
#!/bin/bash
echo $1
echo $2
echo $3
echo $# #统计你输入多少个参数
[root@server0 /]# /root/3.sh aa bb cc dd
aa
bb
cc
4
$? 程序退出后的状态值,0表示正常,其他值异常(可以反映上一个程序执行是否正常)

============================================================================================================================
条件测试
Shell测试的依据
·命令行/程序的退出状态值$?
-值为0,表示执行成功
-值不为0,表示执行异常或失败·在脚本中自定义退出状态值
-以退出之前最后一条命令的$?作为脚本的退出状态值
-也可以自行替换,添加exit 整数
测试操作
·几种可用的测试方式
-正常的命令行
- test -选项 参数.…
– [ 测试表达式 ] #每一部分都要有空格
[root@server0 ~]# id fleyd &>/dev/null //测试操作
[root@server0 ~]# echo $? //状态值为1,表示失败
1
[root@serverO ~]#[ 100 -gt 50]
[root@server0 ~]# echo $? //状态值为0,表示成功
0
[root@serverO ~]#[ $USER == 'student' ]
[root@server0 ~]# echo $?
1 //说明当前用户不是student
常用的测试选项
• 检查文件状态
-e:存在为真
-d:存在,且必须为目录才为真
-f:存在,且必须为文件才为真
[root@server0 /]# [ -e /etc ] #判断/etc目录是否存在
[root@server0 /]# echo $?
0 #表示正常
[root@server0 /]# [ -e /ete ] #判断/ete目录是否存在
[root@server0 /]# echo $?
1 #非0都表示异常
[root@server0 /]# [ -d /etc/passwd ]
[root@server0 /]# echo $?
1
[root@server0 /]# [ -f /etc/passwd ]
[root@server0 /]# echo $?
0
• 比较整数大小
-gt:大于
-ge:大于等于
-eq:等于
-ne:不等于
-lt:小于
-le:小于等于
[root@server0 /]# [ 1 -eq 2 ] #判断是否相等
[root@server0 /]# echo $?
1
[root@server0 /]# [ 10 -gt 11 ] #判断10是否大于11
[root@server0 /]# echo $?
1
[root@server0 /]# [ 10 -ge 10 ] #判断10是否大于等于10
[root@server0 /]# echo $?
0
[root@server0 /]# [ 10 -gt 10 ] #判断10是否大于10
[root@server0 /]# echo $?
1
• 字符串比对
==:一致为真
!=:不一致为真
[root@server0 /]# [ dc == tc ]
[root@server0 /]# echo $?
1
[root@server0 /]# [ $USER == student ]
[root@server0 /]# echo $?
1
[root@server0 /]# [ $USER == root ]
[root@server0 /]# echo $?
0
[root@server0 /]# [ dc != tc ]
[root@server0 /]# echo $?
0
####################################################
if选择结构
if单分支处理
单分支:当条件满足时,作xx处理
-如果服务器CPU负载超标,发送告警邮件

if双分支处理
双分支:当条件满足/不满足时,分别作xx、yy处理- 如果软件包foo未装,则将其安装
-否则,放弃安装

if [ 条件测试 ];then
命令序列xx
else
命令序列yy
fi
[root@server0 /]# vim /root/if01.sh
#!/bin/bash
if [ $1 -eq 1 ];then
echo I Love Dc
else
echo Hello World
fi
[root@server0 /]# chmod +x /root/if01.sh
[root@server0 /]# /root/if01.sh 1
[root@server0 /]# /root/if01.sh 2
案例:判断用户是否输入参数
[root@server0 /]# vim /root/if02.sh
#!/bin/bash
if [ $# -eq 0 ];then #判断用户输入参数的个数是否为0
echo 您没有输入任何参数
else
echo 您输入了参数,一共$#个参数
fi
[root@server0 /]# chmod +x /root/if02.sh
[root@server0 /]# /root/if02.sh
[root@server0 /]# /root/if02.sh harry
案例:利用 read进行获得用户,所输入的用户名
进行判断 如果当前系统有该用户,则输出用户已存在
如果当前系统没有该用户,则创建该用户
[root@server0 /]# vim /root/if03.sh
#!/bin/bash
read -p '请输入您要测试的用户名:' a
id $a &> /dev/null
if [ $? -eq 0 ];then #$? 上个id $a &> /dev/nul是否运行成功
echo 用户$a已存在
else
useradd $a
echo 用户不存在,已经将$a创建成功
fi
[root@server0 /]# chmod +x /root/if03.sh
[root@server0 /]# /root/if03.sh
#############################################
if多分支处理
多分支:当条件1满足时,作xx处理;否则继续检查条件2,若成立则作yy处理;否则,作zz处理
-如果软件包foo未装,则将其安装
-否则,如果已装的软件包foo版本比较旧,则将其升级-再否则,放弃安装

if [条件测试1];then
命令序列xx
elif [条件测试2];then
命令序列yy
elif [条件测试3];then
命令序列aa
else
命令序列zz
fi
案例:利用read获取用户的成绩
进行判断 如果 成绩大于等于90,则输出 优秀
如果 成绩大于等于80,则输出 良好
如果 成绩大于等于70,则输出 一般
如果 成绩大于等于60,则输出 合格
以上条件均不满足,再牛的肖邦也谈不出哥的悲伤
[root@server0 /]# vim /root/if04.sh
#!/bin/bash
read -p '请输入您的成绩:' num
if [ $num -ge 90 ];then #判断用户成绩是否大于等于90
echo 优秀
elif [ $num -ge 80 ];then #判断用户成绩是否大于等于80
echo 良好
elif [ $num -ge 70 ];then #判断用户成绩是否大于等于70
echo 一般
elif [ $num -ge 60 ];then #判断用户成绩是否大于等于60
echo 合格
else
echo 再牛的肖邦也弹不出哥的悲伤
fi
[root@server0 /]#
###################################################
for循环结构:重复性的操作
for循环处理
• 遍历/列表式循环
– 根据变量的不同取值,重复执行xx处理

for 变量名 in 值列表
do
重复性执行的代码
done
for 献血车 in zhangsan lisi wangwu
do
抽血
done
[root@server0 /]# vim /root/for01.sh
#!/bin/bash
for a in zhangsan lisi wangwu haha
do
useradd $a &> /dev/null
echo $a创建成功
done
[root@server0 /]# chmod +x /root/for01.sh
[root@server0 /]# /root/for01.sh
列表值可以不参与循环执行的代码
造数工具:制造连续范围的数字
{起始值..结束值}
[root@server0 /]# vim /root/for01.sh
#!/bin/bash
for a in {1..1000}
do
echo I Love Dc $a
done
[root@server0 /]#
#################################################
案例4:编写一个判断脚本
在 server0 上创建 /root/foo.sh 脚本
1)当运行/root/foo.sh redhat,输出为fedora
2)当运行/root/foo.sh fedora,输出为redhat
3)当没有任何参数或者参数不是 redhat 或者fedora时,
其错误输出产生以下信息: /root/foo.sh redhat|fedora
方法一:
[root@server0 /]# vim /root/foo.sh
#!/bin/bash
if [ $# -eq 0 ];then #判断用户是否输入参数
echo '/root/foo.sh redhat|fedora'
elif [ $1 == redhat ];then #判断输入是否为redhat
echo fedora
elif [ $1 == fedora ];then #判断输入是否为fedora
echo redhat
else
echo '/root/foo.sh redhat|fedora' #单引取消特殊字符含义
fi
方法二(优化):
[root@server0 /]# vim /root/foo.sh
#!/bin/bash
# $# -eq 0 判断用户是否输入参数
# >&2 将输出变为错误输出
# exit 可以指定程序退出的状态值
if [ $# -eq 0 ];then
echo '/root/foo.sh redhat|fedora' >&2
exit 38
elif [ $1 == redhat ];then
echo fedora
elif [ $1 == fedora ];then
echo redhat
else
echo '/root/foo.sh redhat|fedora' >&2
exit 39
fi

#用echo $? 检测不会再输出0,在输入参数时候,而是输出exit 的39,表示有异常‘/root/foo.sh redhat|fedora’
在没有输入参数时,输出exit 的38
###################################################
案例5:编写一个批量添加用户脚本
在 server0 上创建 /root/batchusers 脚本
1)此脚本要求提供用户名列表文件作为参数
2)如果没有提供参数,此脚本应该给出提示
Usage: /root/batchusers,退出并返回相应值
3)如果提供一个不存在的文件,此脚本应该给出提
示 Input file not found,退出并返回相应值
4)新用户的登录Shell为 /bin/false,无需设置密码
5)用户列表测试文件:
http://classroom/pub/materials/userlist

#给一个文件,文件内容是姓名,可以循环读取创建出来
[root@server0 ~]# vim /root/batchusers
#!/bin/bash
if [ $# -eq 0 ];then #用户是否输入东西
echo 'Usage: /root/batchusers' >&2 #没输参数报错,Usage: /root/batchusers
exit 1 #退出并返回相应值1
elif [ -f $1 ];then #判断文件存在为真(-f说明输了参数,且是文件)
for a in $(cat $1) #将命令的输出作为循环的列表值
do
useradd -s /bin/false $a &> /dev/null
echo $a用户创建成功
done
else
echo 'Input file not found' >&2
exit 2
fi

利用命令替换取值
·使用$(命令行)操作
一先执行括号内的命令行,提取此命令行的标准输出
-然后将标准输出结果替换整个$()表达式
-可以作为参数嵌入到其他命令行
[root@server0 ~]# wget http://classroom/pub/materials/userlist
.. ..
[root@server0 ~]# cat /root/userlist
duanwu
zhongqiu
zhsan
lisi
[root@server0~]# echo $(cat /root/userlist)
duanwu
zhongqiu
zhsan
lisi

浙公网安备 33010602011771号