shell脚本

1/81
shell
shell变量
shell的变量
常量 固定的字符或字符串 不能变 所有被赋值的字符串都被称为常量
= 赋值符号
变量 值可以发生变化
y=123 变量赋值,把=右边的内容赋值到等号左边
变量名称:只能由字母、数字和下划线组成 不能以数字开头 见名知意(变量就是会变化的量)
变量的类型:
1.自定义变量
2.环境变量
3.位置变量
4.特殊变量 预定义变量
说明:shell脚本中定义变量是无需指定变量类型的。shell脚本中的变量类型有变量的值来决定。如果值是
数字,其类型自动识别成"整型";如果值用" "双引号、字母就自动识别成字符型。
C、java、数据库中常见的变量类型有整型int、浮点型float、字符型char等。
1.自定义变量 局部变量
定义变量?
变量名=变量的内容

a=80

只对当前shell生效
子shell不生效
如何引用变量?

echo $a

查看所有变量(包含自定义变量和环境变量)
#set
取消变量?

unset a

完成整测试:a=80 ; echo $a ; unset a ; echo $a
2.环境变量 也称作全局(global)变量
用来指定操作系统运行环境的一些参数
在父shell里面设置的变量在他的子shell里面生效的话,说明这个变量拥有继承性,我们可以把拥有继承性
的变量称为环境变量,环境变量都可以在env查看到
2/81
查看环境变量
env
常用的环境变量(环境变量名通常用大写字母) 输出环境变量的值: echo $HOSTNAME
HOSTNAME=client.qf.com //表示当前主机名
SHELL=/bin/bash //表示当前shell的类型
HISTSIZE=1000 //表示当前历史记录的条数
USER=root //表示当前登陆的用户
PWD=/root //表示当前路径
LANG=zh_CN.UTF-8 //表示当前使用的语言
HOME=/root //表示当前用户的家目录
PS1='[\u@\h \W]\$ ' //表示一级提示符
PS2='> ' //表示二级提示符
UID=0 //表示当前用户的uid
MAIL=/var/spool/mail/root //表示当前用户的邮箱位置
PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 以:分
隔 存放命令的目录 表示使用命令不需要加路径使用 凡是在path路径下的命令可以在任何路径下执行

echo $RANDOM //产生0-32767的随机数

31888

echo $(($RANDOM%10)) //产生0-9的随机数

echo $(($RANDOM%100+1)) //产生0-100的随机数

练习A:采用 命令的逻辑执行功能显示当前用户的身份判断,判断,如果uid的值为0时就提示'root user',
否则提示'not root user'。脚本中要用UID这个环境变量。
[ $UID -eq 0 ] && echo 'root user.'
echo 'not root user.'
练习B:采用 命令的逻辑执行功能显示当前用户的身份判断,如果USER的值为root时就提示'root user',否
则提示'not root user'。脚本中要用USER这个环境变量。
[ $USER == "root" ] && echo 'root user.'
echo 'not root user.'
PATH环境变量:作用是记录系统查找命令文件默认路径的变量。在windows、Linux中都有PATH环境变
量。当用户输入某个命令回车后,系统会自动到当前目录和PATH环境变量所设置的目录下查找这个命令文
件,如果有此命令,就执行,否则提示"未找到命令...".
例:执行如下操作,熟悉PATH环境变量的功能。
echo $PATH
lsblk
xxx
AP=$PATH
echo $AP
PATH=/:/etc 临时修改PATH环境变量的值为/、/etc目录
lsblk 提示“未找到命令...”
exit
重新登录,再次执行lsblk看结果。
win7/10的cmd命令行查看PATH环境变量的值:
echo %PATH%
修改PATH 用:隔开
PATH=$PATH:/命令所在目录的路径
安装apache软件
3/81
apachectl 命令所在位置/usr/local/bin/apachectl
想在系统任意位置使用apachectl
两种方法
1.将/usr/local/apachectl命令拷贝到/bin PATH定义的目录下
2.设置环境变量
临时设置
1)PATH=$PATH:/usr/local/apache/bin 自定义变量
export PATH 把自定义变量转为环境变量
2)export PATH=$PATH:/usr/local/apache/bin 直接设置环境变量
永久设置 写到4个环境变量的配置文件(shell 脚本) 开机电脑自动读取配置文件内容
/etc/profile
/etc/bashrc
~/.bash_profile
~/.bashrc
适用范围
/etc 对所有用户生效
~/ 对当前用户生效
登陆shell的类型
登陆shell 4个环境变量的配置都读 敲了登陆用户名就是登陆shell
非登陆shell 只读2个bashrc文件 没有就是非登陆
例1:
[root@client Desktop]# url=www.baidu.com.cn
[root@client Desktop]# vim test.sh
#!/bin/bash
#test 自定义变量和环境变量的作用范围
echo $url
echo $USER
echo $UID
echo $SHELL
测试:
[root@client Desktop]# bash test.sh
root
0
/bin/bash
[root@client Desktop]# . test.sh
www.baidu.com.cn
root
0
/bin/bash
例2:
[root@client Desktop]# vim test.sh
#!/bin/bash
#test 自定义变量和环境变量的作用范围
export url=www.baidu.com.cn
echo $url
echo $USER
4/81
echo $UID
echo $SHELL
测试:
[root@client Desktop]# bash test.sh
www.baidu.com.cn
root
0
/bin/bash
[root@client Desktop]# . test.sh
www.baidu.com.cn
root
0
/bin/bash
3.位置变量,也称位置参数
作用:是将命令执行是输入的某个值传递到脚本内部使用,脚本内部用$1~${n}来接收这些参数。
$1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}……
例3:
[root@client Desktop]# vim test.sh
#!/bin/bash
echo "欢迎使用$0脚本"
echo "第1个位置参数是$1"
echo "第2个位置参数是$2"
echo "第3个位置参数是$3"
echo "第4个位置参数是$4"
echo "第5个位置参数是$5"
echo "第6个位置参数是$6"
echo "第7个位置参数是$7"
echo "第8个位置参数是$8"
echo "第9个位置参数是$9"
echo "第10个位置参数是${10}"
echo "$0运行时的位置参数有$@"
echo "$0运行时的位置参数有$"
echo "$0脚本的PID是$$"
echo "$0脚本运行时的位置参数共$#个"
测试:
[root@client Desktop]# bash test.sh sdf qq dd ccc dsd dhjg 66 55 44 33 22 11 00
练习:编写一个名称为/sh/add_users.sh的脚本,要求用 add_users.sh tom jack lucy的方式运行脚
本,在脚本中使用位置变量$@来接收用户名tom jack lucy信息,批量创建这3个用户,并查询用户的id
信息。
vim /sh/add_users.sh 脚本内容如下
#!/bin/bash
echo $@
for i in $@
do
useradd $i
id $i
done
5/81
#以调试方式运行脚本:
sh -x add_users.sh tom jack lucy
例:用read命令的-a数组选项来实现输入多个用户名,用for循环批量创建这些用户。
#!/bin/bash
read -p '请输入多个用户名:' -a USERS
echo "您输入了${#USERS[@]} 个用户名:${USERS[@]}"
for i in ${USERS[@]}
do
useradd $i
id $i
done
4.预定义变量(必须记住)
$? 上一个命令的返回值 0 正确执行 非0都是错误执行
$0 脚本名
$$ 当前进程的PID
$
所有的参数 $@
$# 参数的个数
[root@client Desktop]# echo $$ //查看当前shell的进程号
3424
影响bash shell的其他文件
bash登陆和欢迎信息(通常用于打广告)
/etc/issue 登陆前显示的信息(本地登陆) ctrl alt f2
/etc/issue.net 登陆前显示的信息(网络登陆)
/etc/motd 登陆后显示的信息
例0:修改本地登录前显示的信息。
[root@client Desktop]# vim /etc/issue 在文件最后添加如下内容
welcome to qf edu.
然后,到虚拟机里面的界面用exit退出登录,看登录提示界面是否多了'welcome to qf edu.'内容。
例1:修改网络登录前显示的信息。
[root@client Desktop]# vim /etc/ssh/sshd_config 在文件最后添加如下内容
Banner /etc/issue.net
[root@client Desktop]# systemctl restart sshd 或 service sshd restart
[root@client Desktop]# vim /etc/issue.net
Red Hat Enterprise Linux Server release 7.6 (Santiago)
Kernel \r on an \m
fei root yonghu jinzhi denglu 添加此行内容即可
测试
[root@today ~]# ssh 192.168.11.11
Red Hat Enterprise Linux Server release 7.6(Santiago)
Kernel \r on an \m
fei root yonghu jinzhi denglu
root@192.168.11.11's password:
6/81
例2:
[root@client ~]# cat /etc/motd
+-------------------------------+
你当前登陆的是网站服务器!
小心你的操作

+-------------------------------+
变量的定义方式:
1.显示赋值
变量名=变量内容
示例:
IPADDR=192.168.1.251
school="Hangzhou qianfeng"
today=date +%F //`和$() 叫做命令替换(命令替换) <br/>[root@client ~]# today=date +%F`
[root@client ~]# echo $today
2017-06-08
[root@client ~]# jintian=$(date +%F)
[root@client ~]# echo $jintian
2017-06-08
2.read 从键盘读入变量值
read -p "提示信息:" 变量名
[root@client ~]# read -p "请输入银行卡帐号:" num
请输入银行卡帐号:4445555666
[root@client ~]# echo $num
4445555666
[root@client ~]# read -p "请输入银行卡密码:" pass
请输入银行卡密码:111222
[root@client ~]# echo "帐号$num 密码$pass" >> /tmp/pass.txt
[root@client ~]# cat /tmp/pass.txt
帐号4445555666 密码111222
-p 指定提示信息
-t 指定超时时间 默认单位:秒
-n 指定字符个数
-a 数组名 将输入的值赋给这个数组名
例1:
7/81
创建用户,提示输入用户名,依据输入的用户名去创建这个用户,创建前先判断用户是否存在,存在提示
用户已创建,不存在创建此用户,提示创建完成
#!/bin/bash
read -t 30 -p "请输入你的用户名:" name
useradd $name &>/dev/null && echo "用户$name创建完成" || echo "用户$name已存在"
例2:
测试本机是否能与输入的ip地址通信,能通信输出ip is up,不能通信 输出ip is down。
#!/bin/bash
read -p "请输入ip地址:" ipaddress
ping -c 3 $ipaddress &>/dev/null && echo "ip is up" ||echo "ip is down"

ping -c 3 192.168.1.251

-c 指定数量
ping 3次自动断开
例3:
使用read截获银行卡的账户和密码
#!/bin/bash
#使用read截获银行卡的账户和密码
read -p "please input bank card account:" account
stty -echo //隐藏显示
read -p "please input bank card passwd:" -n 6 -t 60 passwd
stty echo //恢复正常
echo
echo "account:$account passwd:$passwd" >> /tmp/bank.txt
echo "account:$account passwd:$passwd" |mail -s "hello success" jim@192.168.1.250
3.变量置换 变量“内容”的删除和替换:
======“内容”的删除========
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo ${#url} 获取变量值的长度
15
[root@client ~]# echo ${url} 标准查看
www.sina.com.cn
[root@client ~]# echo ${url#.} 从前向后匹配,最短匹配
sina.com.cn
[root@client ~]# echo ${url##
.} 从前向后匹配,最长匹配 贪婪匹配(找到最后一个.)
cn
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo ${url}
www.sina.com.cn
[root@client ~]# echo ${url%.} 从后向前匹配,最短匹配
www.sina.com
[root@client ~]# echo ${url%%.
} 从后向前匹配,最长匹配 贪婪匹配(找到最前面一个.)
www
========变量的替换==============
[root@client tmp]# url=www.sina.com.cn
[root@client tmp]#
[root@client tmp]# echo ${url/sina/baidu}
www.baidu.com.cn
8/81
[root@client tmp]# echo ${url}
www.sina.com.cn
[root@client tmp]# echo ${url/n/N} 匹配一个替换
www.siNa.com.cn
[root@client tmp]# echo ${url//n/N} 贪婪匹配
www.siNa.com.cN
=======变量的替代============
${变量名-新的变量值}
变量没有被赋值:会使用“新的变量值”替代
变量有被赋值(包括空值):不会被替代
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=111
[root@client tmp]# var3=
如果变量没有被赋值,则显示aaaa
[root@client tmp]# echo ${var1-aaaa}
aaaa
如果变量值有赋值,则不显示222
[root@client tmp]# echo ${var2-222}
111
如果变量值有赋值,值为空,则不显示333
[root@client tmp]# echo ${var3-333}
${变量名:-新的变量值}
变量没有被赋值(包括空值):都会使用“新的变量值”替代
变量有被赋值:不会被替代
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]#
[root@client tmp]# var2=
[root@client tmp]# var3=111
如果变量没有被赋值,则显示aaaa
[root@client tmp]# echo ${var1:-aaaa}
aaaa
如果变量有赋值,值为空,则显示aaaa
[root@client tmp]# echo ${var2:-aaaa}
aaaa
如果变量有赋值,则不显示aaaa
[root@client tmp]# echo ${var3:-aaaa}
111
${变量名+新的变量值}
[root@client tmp]# unset var1
9/81
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,则不显示新的值
[root@client tmp]# echo ${var1+222}
如果变量有赋值,则显示新的值
[root@client tmp]# echo ${var2+222}
222
如果变量有赋值,值为空,则显示新的值
[root@client tmp]# echo ${var3+222}
222
${变量名:+新的变量值}
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]#
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,则不显示新的值
[root@client tmp]# echo ${var1:+222}
如果变量有赋值,则显示新的值
[root@client tmp]# echo ${var2:+222}
222
如果变量有赋值,值为空,则不显示新的值
[root@client tmp]# echo ${var3:+222}
${变量名=新的变量值}
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,则显示新的值
[root@client tmp]# echo ${var1=123}
123
如果变量有赋值,则不显示新的值
[root@client tmp]# echo ${var2=123}
aaaa
如果变量有赋值,值为空,则不显示新的值
[root@client tmp]# echo ${var3=123}
10/81
${变量名:=新的变量值}
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,则显示新的值
[root@client tmp]# echo ${var1:=123}
123
如果变量有赋值,则不显示新的值
[root@client tmp]# echo ${var2:=123}
aaaa
如果变量有赋值,值为空,则显示新的值
[root@client tmp]# echo ${var3:=123}
123
${变量名:num1}
${变量名:num1:num2}
PS1环境变量
默认的PS1环境变量值设置:
echo $PS1 显示如下信息
PS1='[\u@\h \W]\$ '
说明:man bash 然后/PS1查找PS1关键字,大约在1555行,有如下的解释
\u 当前登录的用户名
\h 当前的主机名
#设置新的PS1环境变量值:
PS1='[\u@\h \W-qf-edu]\$ '
echo $PS1 显示如下信息
[root@node11 ~-qf-edu]
练习:将PS1环境变量分别设置成如下效果,看命令提示有何不同。
echo $PS1
PS1='[\u@\h \W]\$ ' 系统默认提示符
PS1='[\t \u@\h \w ]\$'
PS1='[\t-qf_edu \u@\h \W]\$ '
11/81
提问:在百度上查如何将PS1提示符设置成彩色字。根据网上的方法测试一下。
附录:
允许通过插入一些反斜杠转义的特殊字符来定制这些提示字符串,这些字符被如下解释:
\a 一个 ASCII 响铃字符 (07)
\d 日期,格式是 "星期 月份 日" (例如,"Tue May 26")
\D{format}
format 被传递给 strftime(3),结果被插入到提示字符串中; 空的 format
将使用语言环境特定的时间格式。花括号是必需的
\e 一个 ASCII 转义字符 (033)
\h 主机名,第一个 `.' 之前的部分
\H 主机名
\j shell 当前管理的作业数量
\l shell 的终端设备名的基本部分
\n 新行符
\r 回车
\s shell 的名称, $0 的基本部分 (最后一个斜杠后面的部分)
\t 当前时间,采用 24小时制的 HH:MM:SS 格式
\T 当前时间,采用 12小时制的 HH:MM:SS 格式
\@ 当前时间,采用 12小时制上午/下午 (am/pm) 格式
\A 当前时间,采用 24小时制上午/下午格式
\u 当前用户的用户名 the username of the current user
\v bash 的版本 (例如,2.00)
\V bash 的发行编号,版本号加补丁级别 (例如,2.00.0)
\w 当前工作目录
\W 当前工作目录的基本部分
! 此命令的历史编号
# 此命令的命令编号
\$ 如果有效 UID 是 0,就是 #, 其他情况下是 $
\nnn 对应八进制数 nnn 的字符
\ 一个反斜杠
[ 一个不可打印字符序列的开始,可以用于在提示符中嵌入终端控制序列
] 一个不可打印字符序列的结束
变量值的处理
3.变量置换 变量的值(即内容)删除和替换:
======“内容”的删除========
#给变量url赋上www.sina.com.cn这个值。
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo $url 或 echo ${url} 标准查看(获取变量的值)
www.sina.com.cn
[root@client ~]# echo ${#url} 获取变量值的长度(即变量值的字符数)
15
12/81
#以下是用#号删除匹配到的关键字左侧的内容。
[root@client ~]# echo ${url#.} 从前向后匹配,最短匹配(删除操作) 想想先来后到这个词
sina.com.cn 理解:删除左边第一个点和左侧的所有内容
[root@client ~]# echo ${url##
.} 从前向后匹配,最长匹配 贪婪匹配(找到最后一个.)
cn 理解:删除最右侧第一个点和这个点左侧的所有内容
#以下是用%号删除匹配到的关键字右侧的内容。
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo ${url}
www.sina.com.cn
[root@client ~]# echo ${url%.} 从后向前匹配,最短匹配
www.sina.com 理解:删除右边第一个点和右侧的所有内容
[root@client ~]# echo ${url%%.
} 从后向前匹配,最长匹配 贪婪匹配(找到最前面一个.)
www 理解:删除左边第一个点和这个点右侧的所有内容
练习:执行url=http://www.baidu.com:8080/music/index.html,然后完成以下操作
1.输出变量url的值。 答:echo $url
2.输出变量url的值的长度(即字符数)是多少。 答: echo ${#url}
3.仅输出变量url值中的http关键词。 答: echo ${url%%:}
4.仅输出变量url值中的index.html关键词。 答: echo ${url##
/}
5.仅输出变量url值中的域名。 答: echo ${url%:} | awk -F/ '{print $NF}'
6.仅输出变量url值中的端口号。 答: echo ${url##
:} | awk -F/ '{print $1}'
附加练习:
仅输出变量url值中的域名: echo $url | awk -F: '{print $2}' |sed 's@/@@'
练习:编写一个/sh/input.sh脚本,要求提示用户输入一个完整的网址(如http://www.163.com:80/
index.php),然后分别用echo输出用户输入的这个网址,显示"协议名称是:" ,"主页是:","域名是:","端
口号是:"。
vim /sh/input.sh 基本内容如下
#!/bin/bash
read -p '输入一个完整的网址(如http://www.163.com:80/index.php):' url
echo "您输入的完整网址是: $url"
echo "协议名称是: ${url%%:
}"
echo "主页是: ${url##/}"
echo "域名是: $(echo $url | awk -F [:/] '{print $4}') "
echo "端口号是: $(echo $url | awk -F [:/] '{print $5}') "
#域名和端口号的信息可以采用如下代码实现:
#d_name=$(echo $url | awk -F [:/] '{print $4}')
#port=$(echo $url | awk -F [:/] '{print $5}')
#echo "域名是: ${d_name} "
#echo "端口号是: $port "
附加思考:
请在学习完if、test、while、正则表达式之后,对/sh/input.sh脚本做优化,优化内容是判断用户输入的
网址格式是否正确,如果正确就输出相关的信息,否则提示用户重新输入。
========变量的替换==============
[root@client tmp]# url=www.sina.com.cn.nh
[root@client tmp]# echo ${url/sina/baidu}
www.baidu.com.cn
13/81
[root@client tmp]# echo ${url}
www.sina.com.cn
[root@client tmp]# echo ${url/n/N} 匹配一个替换
www.siNa.com.cn
[root@client tmp]# echo ${url//n/N} 贪婪匹配(整行替换)
www.siNa.com.cN.hN
注意:以上对变量值的内容做删除、替换之后,变量的原始值是不发生改变。
例:执行如下操作。熟悉变量值的内容删除、替换等操作。
url=www.sina.com.cn.nh
a=${url//n/N}
b=${url##
.}
c=${url%%.*}
echo $a
echo $b
echo $c
echo $url
=======变量的替代============
要点说明:以下是分别用-、+、=、:等符号来对变量的原始值做判断后进行修改或不修改处理。
${变量名-新的变量值}
变量没有被赋值:会显示“新的变量值”
变量有被赋值(包括空值):显示原值,不显示新值
[root@client tmp]# unset var1 取消/删除var1这个变量
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=111
[root@client tmp]# var3=
如果变量没有被赋值,则显示aaaa
[root@client tmp]# echo ${var1-aaaa}
aaaa
附加测试:echo $var1 发现原值不变
如果变量值有赋值,则不显示222,但是显示变量的原值
[root@client tmp]# echo ${var2-222}
111
如果变量值有赋值,值为空,则不显示333,但是显示变量的原值(即空值)
[root@client tmp]# echo ${var3-333}
${变量名:-新的变量值}
变量没有被赋值(包括空值):都会显示“新的变量值”
变量有被赋值:不会被替代
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=111
[root@client tmp]# var3=
如果变量没有被赋值,则显示aaaa
[root@client tmp]# echo ${var1:-aaaa}
14/81
aaaa
附加测试:echo $var1 发现原值不变
如果变量有赋值,值为空,则显示aaaa
[root@client tmp]# echo ${var2:-aaaa}
111
如果变量有赋值,就不显示aaaa
[root@client tmp]# echo ${var3:-aaaa}
aaaa
${变量名+新的变量值}
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,就不显示新的值
[root@client tmp]# echo ${var1+222}
如果变量有赋值,就显示新的值
[root@client tmp]# echo ${var2+222}
222
如果变量有赋值,值为空,则显示新的值
[root@client tmp]# echo ${var3+222}
222
${变量名:+新的变量值}
[root@client tmp]# unset var1 unset var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,就不显示新的值
[root@client tmp]# echo ${var1:+222}
如果变量有赋值,就显示新的值
[root@client tmp]# echo ${var2:+222}
222
如果变量有赋值,值为空,则不显示新的值
[root@client tmp]# echo ${var3:+222}
${变量名=新的变量值}
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,就显示新的值,并且会将新值赋给这个变量。
[root@client tmp]# echo ${var1=123}
123
如果变量有赋值,则不显示新的值
15/81
[root@client tmp]# echo ${var2=123}
aaaa
如果变量有赋值,值为空,则不显示新的值
[root@client tmp]# echo ${var3=123}
${变量名:=新的变量值}
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果变量没有被赋值,就显示新的值,并且会将新值赋给这个变量。(必知)
[root@client tmp]# echo ${var1:=123}
123
附加测试:echo $var1 发现变量var1有了新值
如果变量有赋值,则不显示新的值
[root@client tmp]# echo ${var2:=123}
aaaa
附加测试:echo $var2 发现原值不变
如果变量有赋值,值为空,就显示新的值,并且会将新值赋给这个变量。(必知)
[root@client tmp]# echo ${var3:=123}
123
${变量名:num1}
${变量名:num1:num2}
实例
练习:编写一个/sh/input.sh脚本,要求提示用户输入一个完整的网址(如http://www.163.com:80/
index.php),然后分别用echo输出用户输入的这个网址,显示"协议名称是:" ,"主页是:","域名是:","端
口号是:"。
vim /sh/input.sh 基本内容如下
#!/bin/bash
read -p '输入一个完整的网址(如http://www.163.com:80/index.php):' url
echo "您输入的完整网址是: $url"
echo "协议名称是: ${url%%:}"
echo "主页是: ${url##
/}"
echo "域名是: $(echo $url | awk -F [:/] '{print $4}') "
echo "端口号是: $(echo $url | awk -F [:/] '{print $5}') "
#域名和端口号的信息可以采用如下代码实现:
#d_name=$(echo $url | awk -F [:/] '{print $4}')
16/81
#port=$(echo $url | awk -F [:/] '{print $5}')
#echo "域名是: ${d_name} "
#echo "端口号是: $port "
例:编写一个/sh/var.sh脚本。要求提示用户输入一个IP地址,做判断测试(如果用户未输入ip),就提示
默认IP是192.168.11.5,否则显示默认IP是用户输入的这个IP值。
vim /sh/var.sh
#!/bin/bash
read -p 'please input ip address:' IP
echo "默认IP是:${IP:=192.168.11.5}"
脚本常见案例(个人整理)
例如:用if的结构1做如下测试。
x=abc;y=abc;z=123
if [ $x = $y ];then
echo yes
fi
.输入一个数字判断是奇数还是偶数
#!/bin/bash
#
read -p "输入一个整数:" num
if [ $(($num % 2)) -eq 0 ]
then
echo "$num是偶数"
else
echo "$num是奇数"
fi
例如:判断系统中是否存在root用户,如果存在就提示yes。
用命令的逻辑执行来实现,方法如下:
id root && echo yes
用if语句来实现,写法如下:
id root
if [ $? -eq 0 ];then
echo yes
fi
例如:判断系统中是否存在/zk目录,如果存在就删除此目录且显示过程,否则创建此目录且显示过程
方法一:用命令的逻辑执行方法来实现的写法。
[ -d /zk ] && rm -rfv /zk || mkdir -pv /zk
方法二:用if语句实现的写法。
17/81
if [ -d /zk ];then
rm -rfv /zk
else
mkdir -pv /zk
fi
例如:判断系统中是否存在zk用户,如果存在就用userdel -r zk删除此用户,否则创建zk用户。
方法一:用命令的逻辑执行方法来实现的写法。
id zk && userdel -r zk || useradd zk
方法二:用if语句实现的写法。
if id zk;then
userdel -r zk
else
useradd zk
fi
例:编写一个名称为/sh/mk.sh的脚本,要求批量创建/test/a1~/test/a5这些目录,同时显示目录创建的执
行过程。
第1步,编写脚本文件。
vim /sh/mk.sh 脚本内容如下
#!/bin/bash
#description: this is a mkdir script.
for i in {1..5}
do
mkdir -pv /test/a$i
done
例:编写一个名称为/sh/user.sh的脚本,要求批量创建用户u1~u5,并且在创建用户之后查用户的id号,并
且给每个用户设置初始登录密码为007。
第1步,编写脚本文件。
vim /sh/user.sh 脚本内容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
done
第3步,对入门级的脚本进行如下优化。
1.在useradd创建用户之前,判断此用户是否存在,如果存在就提示user exsits,否则创建此用户并设置初
始登录密码为007.
cp -av /sh/user.sh /sh/user-new.sh
vim /sh/user-new.sh 脚本内容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
if (id u$i);then
echo "u$i user exsits."
else
18/81
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
fi
done
练习:在命令行中执行以下操作,实现输出10以内的正整数。
i=1
while [ $i -le 10 ]
do
echo $i
let i++ 或 $[i++] 或 $((i++))
sleep 1s 等待1秒(停顿1秒)
done

例:编写一个名称为/sh/while_user.sh的脚本,要求用while循环语句,批量创建用户w1~w5,并且在创建
用户之后查用户的id号,并且给每个用户设置初始登录密码为007。
第1步,编写脚本文件。
vim /sh/while_user.sh
i=1
while [ $i -le 5 ]
do
useradd w$i && echo "w$i user added." || echo "w$i user exsits."
id w$i
echo 007 | passwd --stdin w$i
let i++
sleep 1s
done
思考:编写一个名称为/sh/del_users.sh的脚本,要求用while循环语句,批量查询用户w1~w5的id信息,然
后用userdel -r删除这些用户。
第1步,编写脚本文件。
vim /sh/del_user.sh
i=1
while [ $i -le 5 ]
do
id w$i
userdel -r w$i && echo "w$i user removed." || echo "w$i user not exsits."
let i++
sleep 1s
done
例如:写一个名称为/sh/cai.sh的脚本,要求提示用户输入数字,判断数字大小是否为520,如果是就提示
yes;如果大于520,就提示bigger;否则提示little。
第1步,编写/sh/cai.sh脚本文件。
mkdir -pv /sh
vim /sh/cai.sh
#!/bin/bash
#description:this is crossword games.
read -p 'Please input your number:' x
if [ $x -eq 123 ];then
echo 'you are right.'
elif [ $x -gt 123 ];then
echo 'you are bigger'
19/81
else
echo 'you are little.'
fi

while死循环(无限循环):
while :
do
cmd_list循环体
done
例:执行如下while死循环语句,实现每隔2秒输出echo命令的中的文本内容。[按ctrl+c强制终止死循环]
while :
do
echo 'I love you!'
sleep 2s
done
例:写一个名称为/sh/cai.sh的脚本,要求用while循环控制语句,当用户猜的数字错了就连续重复猜(即提示
用户"'Please input your number"),提示用户输入数字,判断数字大小是否为520,如果是就提示yes;
如果大于520,就提示bigger;否则提示little。
第1步,编写/sh/cai-2.sh脚本文件。
mkdir -pv /sh
vim /sh/cai-2.sh
#!/bin/bash
#description:this is crossword games.
x=0
while [ $x -ne 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
break(猜对了退出死循环)
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
until循环体退出循环
例:在命令行中执行如下操作,实现用until循环来输出1~10这些数。
i=1
until [ $i -gt 10 ]
do
echo $i
let i++
done
将while语句的猜字游戏脚本/sh/cai-2.sh进行改写,用until语句来实现。
第1步,编写/sh/cai-3.sh脚本文件。
mkdir -pv /sh
vim /sh/cai-3.sh
#!/bin/bash
#description:this is crossword games.
x=0
20/81
until [ $x -eq 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
循环实例:
1.用for输出1~100的求和结果。
2.用for语句输出等腰直角三角形。
3.用for语句输出九九乘法口诀表。
例1:编写一个名称为/sh/100jia.sh的脚本,要用for进行循环控制,实现输出1+2+...+100的计算结果。
#!/bin/bash
sum=0
for ((i=0;i<=100;i++))
do
sum=$[i+sum]
done
echo $sum
例2:编写一个名称为/sh/3ja.sh的脚本,用for进行循环控制,实现在屏幕上显示一个5行由号组成的等腰
直角三角形。

**




解题思路:外层for循环控制三角形中星号的行数,内层for循环控制三角形中星号的列数。
#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=1;j<=i;j++))
do
echo -n ""
done
echo " "
done
倒立的三角形
#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=5;j>=i;j--))
do
echo -n "
"
done
echo
done
循环分析:for循环中每次i、j变量的取值分析。
21/81
第一次循环:
i=1 j=1
换行
第二次循环:
i=2 j=1
i=2 j=2 换行
第二次循环:
i=3 j=1
i=3 j=2
i=3 j=3
换行
第四、五次循环依次类推。
例3:编写一个名称为/sh/99.sh的脚本,用for进行循环控制,实现在屏幕上显示'九九乘法表口诀'。
1X1=1
1X2=2 2X2=4
1X3=3 2X3=6 3X3=9
……
1X9=9 2X9=18 …… 9X9=81
#!/bin/bash
for ((i=1;i<=9;i++))
do
for ((j=1;j<=i;j++))
do
echo -ne "${j}X${i}=$[ij]\t"
done
echo
done
case语句
例:编写一个名称为/sh/menu.sh的脚本,要求显示一个主菜单界面,提示用户输入功能选项,回车确认后
执行指定选项的命令操作。
第1步,根据项目需求,编写出脚本内容。
vim /sh/menu.sh 入门级脚本内容如下:
echo '---------------------
1/a.Install NFS Service
2/b.Install Vsftpd Service
3/c.Install Samba Service
4/d.Install DNS Service
22/81
5/e.Install Apache Service
6/f.Install PXE Service
7/g.Install DHCP Service
0/
.Exit Shell Script
---------------------'
read -p 'please input your choice:' opt
case $opt in
1|a)
echo 'Install NFS Service'
. /sh/nfs-new.sh
;;
2|b)
echo 'Install Vsftpd Service'
. /sh/ftp-new.sh
;;
0|)
echo 'Exit Shell Script'
#exit 0
;;
esac
第2步,给脚本添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/menu.sh
. /sh/menu.sh
23/81
5.交互式脚本
需求:提示用户输入功能选项,选项1为执行clear、date、创建jack用户、设置jack密码功能;选项2为执
行clear、删除jack用户;如果输入其他字符则提示“未输入正确的功能选项,程序退出”,且自动退出脚
本。
vi case1.sh 代码内容如下
#!/bin/bash
read -p "请输入功能选项数字代号,如1、2...:" choice
case $choice in
1)
clear
date
useradd jack
echo jack | passwd --stdin jack
;;
2)
clear
id jack && userdel -r jack || echo "jack用户不存在"
;;
)
echo "未输入正确的功能选项,程序退出"
exit 1
esac
6.脚本中交互式实现
判断用户输入的字符串,
如果用户输入的字符串为start,就在/tmp下创建一个start文件;
如果用户输入的为stop,那么就删除/tmp/start文件;
如果用户输入的为restart,那么就先删除/tmp/start文件,然后创建一个start1文件;
如果用户输入其他的字符串,就输出一个帮助信息:脚本名 Usage:{start|stop|restart}
read -p "请输入字符串:" strings
case $strings in
start)
touch /tmp/start
;;
stop)
rm -rf /tmp/start
;;
restart)
if [ -e /tmp/start ]
then
rm -rf /tmp/start
else
touch /tmp/start1
fi
;;

echo "$0 Usage:{start|stop|restart}"
esac
1.超市卖水果
24/81
你输入苹果,显示 苹果 5元每斤
你输入香蕉 ,显示 香蕉 3元每斤
你输入橘子,显示 橘子 3元每斤
如果你输入的不是苹果 香蕉 橘子 就提示只能查询 苹果 香蕉 橘子
case语句#!/bin/bash 可以把红色的分别换成0,1,2或者apple|0),banana|1),orange|2)
read -p "输入要查询价格的水果名:" aa
case $aa in
apple)
echo "apple 5元每斤";;
banana)
echo "banana 3元每斤";;
orange)
echo "orange 3元每斤";;
)
echo "Usage :{apple|banana|orange}"
esac
for语句#!/bin/bash
num=(apple banana orange )
declare -a num
read -p "please input fruits:" aa
if [ $aa == ${num[0]} ];then
echo "$aa 5元一斤“
elif [ $aa == ${num[1]} ];then
echo "$aa 5元一斤"
elif [ $aa == ${num[2]} ];then
echo "$aa 2元一斤"
else
echo "Usage:{apple|banana|orange}"
fi
最简单的×××,但是红球有可能重复
vim /sh/cp.sh 脚本内容如下
#!/bin/bash
for i in {1..6}
do
red[$i]=$[$RANDOM%33+1]
echo -ne "${red[$i]}\t"
done
echo
echo "$[$RANDOM%16+1]"
25/81
初级脚本优化项目案例
编写脚本的思路:
1.根据目标需求分析需要用到哪些操作命令。
2.将操作的命令写入到shell脚本文件中。不考虑逻辑判断。(入门级)
3.运行和测试入门级的脚本。
4.对入门级的脚本进行优化,即添加条件判断if、循环(while、until、for)等逻辑控制语句。(高级脚本)
5.运行和测试高级的脚本。
做一个menu菜单
vim /sh/menu.sh 入门级脚本内容如下:
#!/bin/bash
echo '---------------------
1/a.Install NFS Service
2/b.Install Vsftpd Service
3/c.Install Samba Service
4/d.Install DNS Service
5/e.Install Apache Service
6/f.Install PXE Service
7/g.Install DHCP Service
0/.Exit Shell Script
---------------------'
_NFS(){
soft='nfs-utils rpcbind'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_Vsftpd(){
soft='vsftpd lftp ftp'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_Samba(){ soft='samba samba-comment samba-client'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_Httpd(){ soft='Httpd'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_DHCP(){ soft='dhcpd'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_PXE(){ soft='vsftpd dhcpd tftp-server '
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_firewalld(){
systemctl stop firewalld
getenforce
}
_yum(){ [ -d /iso ] && echo '/iso is exists' || mkdir -pv /iso
lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso
cd /etc/yum.repos.d
[ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak
mv -fv
.repo bak
echo '[centos7.6]
26/81
name=centos 7.6 linux
baseurl=file:///iso
enabled=1
gpgcheck=0
' >/etc/yum.repos.d/iso.repo
mount /dev/sr0 /iso
yum clean all
yum repolist
}
_addusers(){ i=wl
id $i && echo 'user is exists' || useradd $i
}
_DNS(){ soft='bind bind-utils'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
read -p '输入功能选项的数字编号:' i
case $i in
1)
_NFS
;;
2)
_Vsftpd
;;
3)
_Samba
;;
4)
_Httpd
;;
5)
_DHCP
;;
6)_PXE
;;
7)_firewalld
;;
8)_yum
;;
9)_addusers
;;
10)_DNS
;;
*)
echo 'input error shell.exit'
;;
esac

例:编写一个名称为/sh/user.sh的脚本,要求批量创建用户u1~u5,并且在创建用户之后查用户的id号,并
且给每个用户设置初始登录密码为007。
第1步,编写脚本文件。
vim /sh/user.sh 脚本内容如下
#!/bin/bash
27/81
#description: this is a useradd script.
for i in {1..5}
do
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
done
对入门级的脚本进行如下优化。
1.在useradd创建用户之前,判断此用户是否存在,如果存在就提示user exsits,否则创建此用户并设置初
始登录密码为007.
cp -av /sh/user.sh /sh/user-new.sh
vim /sh/user-new.sh 脚本内容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
if (id u$i);then
echo "u$i user exsits."
else
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
fi
done
需求:编写一个名称为/sh/nfs.sh的脚本程序,要求实现查询NFS软件是否已安装(nfs-utils、rpcbind),全
自动安装(nfs-utils、rpcbind)文件共享服务,自动启动服务,自动以可读可写方式共享/share目录,自动本
地测试查看nfs共享资源。
首先,编写入门级的脚本。
第1步,编写nfs.sh脚本文件。
vim /sh/02.sh
#!/bin/bash
rpm -q nfs-utils rpcbind
yum install -y nfs-utils rpcbind
systemctl restart nfs rpcbind
systemctl enable nfs rpcbind
mkdir -pv /share
chmod -v o+rwx /share
echo '/share (rw,no_root_squash)' > /etc/exports
exportfs -rav
showmount -e 127.0.0.1
优化后的脚本内容如下:
cp -av /sh/nfs.sh /sh/nfs-new.sh
vim /sh/nfs-new.sh
#!/bin/bash
rpm -q nfs-utils rpcbind > /dev/null && echo 'soft exsits' || yum install -y nfs-utils rpcbind
systemctl status nfs | grep dead && systemctl restart nfs rpcbind || echo 'service running'
read -p 'Input your share dir path (e.g. /etc):' dir_path
[ -d $dir_path ] && echo 'dir exsits' || (mkdir -pv $dir_path;chmod -v o+rwx $dir_path)
grep -q "$dir_path" /etc/exports && echo 'share exsits' || echo "$dir_path
(rw)" >> /etc/
exports
exportfs -rav
showmount -e 127.0.0.1
第4步,测试新脚本的运行。
. /sh/nfs-new.sh
28/81

需求:编写一个名称为/sh/ftp.sh的脚本程序,要求实现查询vsftpd软件是否已安装,全自动安装vsftpd文
件共享服务,自动启动服务,自动创建/var/ftp/dvd目录,将光盘(/dev/cdrom或/dev/sr0)挂载到/var/ftp/
dvd目录中,用lftp做访问vsftpd共享的内测(本地测试127.0.0.1)。
第1步,编写ftp.sh脚本文件。
vim /sh/ftp.sh
#!/bin/bash
rpm -q vsftpd lftp ftp
yum install -y vsftpd lftp ftp
systemctl restart vsftpd
systemctl enable vsftpd
mkdir -pv /var/ftp/dvd
mount -v /dev/cdrom /var/ftp/dvd
mount | grep ftp
lftp 127.0.0.1 -e 'ls dvd;ls;bye'
第3步,对入门级的脚本ftp.sh做如下优化:
1.判断软件是否已安装,如果已安装就提示soft exsits,否则安装软件。
2.判断服务是否已启动,如果未启动就重启服务,否则提示service running。
3.提示用户输入共享用户账号。
4.判断输入的用户账号是否存在,如果存在就提示user exsits,否则创建此用户且给用户设置登录密码为
01。
5.用lftp命令采用此用户来访问共享,列出共享文件名列表。
cp -av /sh/ftp.sh /sh/ftp-new.sh
vim /sh/ftp-new.sh 优化后的脚本内容如下:
#!/bin/bash
rpm -q vsftpd lftp ftp > /dev/null && echo 'soft exsits' ||yum install -y vsftpd lftp ftp
systemctl status vsftpd | grep -q dead && systemctl restart vsftpd || echo 'service running'
systemctl enable vsftpd
mkdir -pv /var/ftp/dvd
mount -v /dev/cdrom /var/ftp/dvd
mount | grep ftp
read -p 'Input your account name:' user_name
id $user_name &> /dev/null && echo 'user exsits.' || (useradd $user_name;echo 01 |
passwd --stdin $user_name)
lftp 127.0.0.1 -u ${user_name},01 -e 'ls -a;bye'
第4步,测试新脚本的运行。
. /sh/ftp-new.sh

需求:编写一个名称为/sh/smb.sh的脚本程序,要求实现查询samba软件是否已安装,全自动安装samba
文件共享服务,自动启动smb服务,创建bk这个samba用户,bk的samba登陆密码为007,自动用samba以
smbrw为共享名称并且以可读可写方式共享/smb目录。做内测(即本地测试127.0.0.1)自动查看samba共享
资源。
第1步,编写smb.sh脚本文件。
vim /sh/smb.sh
#!/bin/bash
rpm -q samba samba-client samba-common
yum install -y samba samba-client samba-common
systemctl restart smb
systemctl enable smb
29/81
useradd bk
pdbedit bk -a
pdbedit -L
mkdir -pv /smb
echo '[smbrw]
comment=smbrw dir share
path=/smb
writeable=yes
browseable=yes
public=yes
' >> /etc/samba/smb.conf
systemctl reload smb
smbclient -L 127.0.0.1

需求:编写一个名称为/sh/apache.sh的脚本程序,要求实现查询httpd软件是否已安装,全自动安装
httpd、curl、elinks文件共享服务,自动启动httpd服务,/baidu/www目录,主页为/baidu/www/
index.html,自动用基于端口的虚拟主机技术用81端口发布/baidu/www目录的网站,虚拟主机配置文件
名为/etc/httpd/conf.d/baidu.conf。做网站的内测(即本地测试127.0.0.1)访问。
第1步,编写apache.sh脚本文件。
vim /sh/apache.sh
#!/bin/bash
rpm -q httpd httpd-manual
yum install -y httpd httpd-manual curl elinks
systemctl restart httpd
systemctl enable httpd
mkdir -pv /baidu/www
echo 'www.baidu.com' > /baidu/www/index.html
echo 'Listen 81
<VirtualHost :81>
ServerAdmin 123@qq.com
ServerName www.baidu.com
DocumentRoot /baidu/www
ErrorLog /var/log/httpd/www.baidu.com-err.log
CustomLog /var/log/httpd/www.baidu.com-access.log common
</VirtualHost>
<Directory /baidu/www>
AllowOverride None
require all granted
</Directory>
' > /etc/httpd/conf.d/baidu.conf
systemctl reload httpd
lsof -i:81
curl 127.0.0.1:81
---yum 配置
需求:编写一个名称为/sh/yum.sh的脚本,要求自动将/dev/cdrom挂载到/iso目录中,移动/etc/
yum.repos.d/
.repo到/etc/yum.repos.d/bak目录中,自动创建yum源配置文件/etc/yum.repos.d/
iso.repo,其中iso.repo文件中的baseurl路径指向/iso目录,自动测试yum源和仓库的可用性(yum clean
all;yum repolist)。
脚本编写的思路:
1.根据需求分析要用到哪些命令。
2.将命令写到脚本文件中,得到第1版的入门级脚本文件。
3.测试入门级脚本的运行。
30/81
4.优化入门级脚本:在脚本中添加if逻辑控制语句,让脚本更具通用性,得到高级脚本。
5.测试高级脚本的运行。
vim /sh/yum.sh
#!/bin/bash
mkdir -pv /iso
mount /dev/cdrom /iso
cd /etc/yum.repos.d
mkdir -pv bak
mv -v .repo bak
echo '[centos7.6]
name=centos 7.6 linux
baseurl=file:///iso
enabled=1
gpgcheck=0
' > /etc/yum.repos.d/iso.repo
yum clean all
yum repolist
4.优化入门级脚本:在脚本中添加if逻辑控制语句,让脚本更具通用性,得到高级脚本。
cp -av /sh/yum.sh /sh/yum-new.sh
vim /sh/yum-new.sh
#!/bin/bash
[ -d /iso ] && echo '/iso directory exsits.' || mkdir -pv /iso
lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso
cd /etc/yum.repos.d
[ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak
mv -fv
.repo bak
echo '[centos7.6]
name=centos 7.6 linux
baseurl=file:///iso
enabled=1
gpgcheck=0
' > /etc/yum.repos.d/iso.repo
yum clean all
yum repolist
DNS域名解析自动部署脚本文件
#!/bin/bash
rpm -q bind bind-utils
yum -y install bind bind-utils
systemctl restart named
systemctl enable named
sed -i 's/127.0.0.1/any/' /etc/named.conf
sed -i 's/localhost/any/' /etc/named.conf
systemctl restart named
echo 'zone "qf.com" IN {
type master;
file "qf.com.zx";
allow-update { none; };
};
zone "5.168.192.in-addr.arpa" IN {
type master;
file "192.168.5.x";
allow-update { none; };
};' >/etc/named.rfc1912.zones
named-checkconf
cp -av /var/named/named.localhost /var/named/qf.com.zx
31/81
cp -av /var/named/named.loopback /var/named/192.168.5.x
echo '$TTL 1D
@ IN SOA qf.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1
NS qf.com.
dns A 192.168.11.11
www A 1.1.1.1
ftp A 1.1.1.2
http A 1.1.1.3
web CNAME www.qf.com.' >/var/named/qf.com.zx
echo '$TTL 1D
@ IN SOA dns.qf.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1
PTR localhost.
NS dns.qf.com.
dns A 192.168.11.11
1 PTR www.qf.com.
2 PTR http.qf.com.
3 PTR ftp.qf.com.' >/var/named/192.168.5.x
systemctl restart named
nslookup www.qf.com 192.168.11.11
nslookup http.qf.com 192.168.11.11
nslookup ftp.qf.com 192.168.11.11
nslookup 192.168.5.1 192.168.11.11
nslookup 192.168.5.3 192.168.11.11
nslookup 192.168.5.2 192.168.11.11
32/81
优化DNS脚本
#!/bin/bash
rpm -q bind bind-utils && echo 'soft is exists' || yum -y install bind bind-utils
systemctl status named | grep dead && (systemctl restart named && systemctl enable named) ||
echo 'service is running'
[ -d /etc/named.conf ] && sed -i 's/127.0.0.1/any/' /etc/named.conf
[ -d /etc/named.conf ] && sed -i 's/localhost/any/' /etc/named.conf
systemctl restart named
[ -d /etc/named.rfc.1912.zones ] && echo 'zone "qf.com" IN {
type master;
file "qf.com.zx";
allow-update { none; };
};' >/etc/named.rfc.1912.zones
cd /var/named
[ -d named.localhost ] && mkdir -pv qf.com.zx
[ -d qf.com.zx ] && echo '$TTL 1D
@ IN SOA qf.com. rname.invalid. (
33/81
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1
NS qf.com.
dns A 192.168.11.11
www A 1.1.1.1
ftp A 1.1.1.2
http A 1.1.1.3
web CNAME www.qf.com.' >/var/named/qf.com.zx
systemctl restart named
nslookup www.qf.com 192.168.11.11
nslookup http.qf.com 192.168.11.11
nslookup ftp.qf.com 192.168.11.11
34/81
作业
1.打印圣诞树
*










1 #!/bin/bash
2 #
3 for ((i=1;i<=4;i++))
4 do
5 for ((j=4;j>=i;j--))
6 do
7 echo -n " "
8 done
9 for ((k=1;k<=2i-1;k++))
10 do
11 echo -n "
"
12 done
13 echo
14 done
15
16 for ((a=1;a<=3;a++))
17 do
18 for ((b=3;b>=a;b--))
19 do
20 echo -n " "
21 done
22 for ((c=1;c<=2a+1;c++))
23 do
24 echo -n "
"
25 done
26 echo
27 done
28
29 for ((f=1;f<=3;f++))
30 do
31 for ((d=1;d<=3;d++))
32 do
33 echo -n " "
34 done
35 for e in {1..3}
36 do
37 echo -n "*"
38 done
39 echo
40 done
35/81

*












1 #!/bin/bash
2 for ((a=1;a<=4;a++))
3 do
4 for b in {1,2}
5 do
6 echo -n " "
7 done
8 for ((c=4;c>=a;c--))
9 do
10 echo -n " "
11 done
12 for ((d=1;d<=a;d++))
13 do
14 echo -n ""
15 done
16 for ((e=2;e<=a;e++))
17 do
18 echo -n "
"
19 done
20 echo
21 done
22
23 for ((f=1;f<=5;f++))
24 do
25 for ((g=5;g>=f;g--))
26 do
27 echo -n " "
28 done
29 for ((h=1;h<=f;h++))
30 do
31 echo -n ""
32 done
33 for i in 1
34 do
35 echo -n "
"
36 done
37 for ((j=1;j<=f;j++))
38 do
39 echo -n ""
40 done
41 echo
42 done
43
44 for ((k=1;k<=3;k++))
36/81
45 do
46 for l in {1..5}
47 do
48 echo -n " "
49 done
50 for m in {1..3}
51 do
52 echo -n "
"
53 done
54 echo
55 done
1 #!/bin/bash
2 #
3 for ((i=1;i<=4;i++))
4 do
5 for ((j=6;j>=i;j--))
6 do
7 echo -n " "
8 done
9 for ((k=1;k<=2i-1;k++))
10 do
11 echo -n "
"
12 done
13 echo
14 done
15
16 for ((a=1;a<=5;a++))
17 do
18 for ((b=5;b>=a;b--))
19 do
20 echo -n " "
21 done
22 for ((c=1;c<=2a+1;c++))
23 do
24 echo -n "
"
25 done
26 echo
27 done
28
29 for ((f=1;f<=3;f++))
30 do
31 for ((d=1;d<=5;d++))
32 do
33 echo -n " "
34 done
35 for e in {1..3}
36 do
37 echo -n "*"
38 done
39 echo
40 done

2.计算器不输入退出就一直等待输入数字进行计算
1 #!/bin/bash
2 #
37/81
3 while read -p "请输入计算的内容:" num
4 do
5 if [[ -z $num || $num == exit ]]
6 then
7 exit
8 else
9 a=$(($num))
10 echo $a
11 fi
12 done
1 #!/bin/bash
2 #
3 while read -p "请输入计算的内容:" num
4 do
5 num=${num:=exit}
6 if [[ $num == exit ]]
7 then
8 exit
9 else
10 a=$(($num))
11 echo $a
12 fi
13 done
3.写一个脚本,显示如下菜单给用户: while
cpu)print cpu information;
disk) print disk information;
mem)print memory information;
quit)quit;
Pleas enter your option:
根据用户输入的显示相应的信息,如果用户输入的不是以上几种就显示帮助信息,帮助信息为“Pleas
enter your option:<cpu|disk|mem|quit>” 该脚本中用户的选择不区分大小写

  1. 编写脚本,计算1+2+3+4...100的和 while until
    1 a=0
    2 i=0
    3 while [ $i -le 100 ]
    4 do
    5 a=$(($a+$i))
    6 let i++
    7 done
    8 echo $a

    1 a=0
    2 i=0
    3 until [ $i -gt 100 ]
    4 do
    5 a=$(($a+$i))
    6 let i++
    7 done
    8 echo $a

38/81
1.编写脚本,如果:
根分区剩余空间小于20%
向用户root发送警告邮件,邮件的内容包含使用率相关信息
#!/bin/bash
#
gsyl=df -h | head -2 |tail -1 | tr -s " " | cut -d " " -f 5 | cut -d "%" -f 1
re=$((100-$gsyl))
if [ $re -lt 20 ]
then
echo "警告:根分区剩余空间为$re%" > /tmp/disk.txt
mail -s "警告信息" root@192.168.1.251 < "/tmp/disk.txt"
fi
2.输入一个数字判断是奇数还是偶数
#!/bin/bash
#
read -p "输入一个整数:" num
if [ $(($num % 2)) -eq 0 ]
then
echo "$num是偶数"
else
echo "$num是奇数"
fi
3.编写脚本,计算1+2+3+4...100的和
1 #!/bin/bash
2 #
3 num=0
4 for i in {1..100}
5 do
6 num=$(($num+$i))
7 done
8 echo $num
4.输入两个数,求和、差、商、积、余。必须使用$1 $2
1 #!/bin/bash
2 #
3 echo "两个数的和是:echo $(($1+$2))"
4 echo "两个数的差是:echo $(($1-$2))"
5 echo "两个数的商是:echo $(($1/$2))"
6 echo "两个数的积是:echo $(($1*$2))"
7 echo "两个数的余是:echo $(($1%$2))"
5.打印下列图形


39/81




1 #!/bin/bash
2 for i in {1..4}
3 do
4 for j in {1..5}
5 do
6 echo -n ""
7 done
8 echo " "
9 done
1 #!/bin/bash
2 for ((i=1;i<=4;i++))
3 do
4 for ((j=1;j<=5;j++))
5 do
6 echo -n "
"
7 done
8 echo " "
9 done
1 read -p "输入行数:" line
2 read -p "输入多少个:" xing
3 for ((i=1;i<=$line;i++))
4 do
5 for ((j=1;j<=$xing;j++))
6 do
7 echo -n "
"
8 done
9 echo " "
10 done
6.
*
**






1 for ((i=1;i<=7;i++))
2 do
3 for ((j=1;j<=i;j++))
4 do
5 echo -n ""
6 done
7 echo " "
8 done
1 read -p "输入行数:" line
2 for ((i=1;i<=$line;i++))
40/81
3 do
4 for ((j=1;j<=i;j++))
5 do
6 echo -n "
"
7 done
8 echo " "
9 done





  1. 1 #!/bin/bash
    2 for ((i=1;i<=4;i++))
    3 do
    4 for ((r=4;r>=i;r--))
    5 do
    6 echo -n "a"
    7 done
    8 for ((f=1;f<=i;f++))
    9 do
    10 echo -n ""
    11 done
    12 for m in seq 2 $i
    13 do
    14 echo -n "
    "
    15 done
    16
    17 echo
    18 done
    1 #!/bin/bash
    2 for ((i=1;i<=4;i++))
    3 do
    4 for ((j=4;j>=i;j--))
    5 do
    6 echo -n " "
    7 done
    8 for ((k=1;k<=2i-1;k++))
    9 do
    10 echo -n "
    "
    11 done
    12 echo
    13 done
    41/81
    1 #!/bin/bash
    2 read -p "输入行数:" num
    3 for ((i=1;i<=$num;i++))
    4 do
    5 for ((j=$num;j>=i;j--))
    6 do
    7 echo -n " "
    8 done
    9 for ((k=1;k<=2i-1;k++))
    10 do
    11 echo -n "
    "
    12 done
    13 echo
    14 done
    7./test目录下有100个文件
    统一给这些文件改名,格式为:a.bak
    1 #!/bin/bash
    2 for i in ls /test
    3 do
    4 mv /test/$i /test/$i.bak
    5 done
    8./test目录下有a.bak aa.bak C.b.bak等以.bak结尾的文件,将这些文件有.bak改名为.txt
    1 for i in ls /test/*.bak
    2 do
    3 mv $i ${i%.*}.txt
    4 done

9.输入J计算1..100内所有奇数相加之和,输入O计算1..100内所有偶数相加之和
1 read -p "请输入J或者O:" num
2 a=0
3 num=$(echo $num | tr "a-z" "A-Z" )
4 if [ "$num" == "J" ]
5 then
6 for i in seq 1 2 100
7 do
8 a=$(($a+$i))
9 done
10 echo $a
11 elif [ "$num" == "O" ]
12 then
13 for i in seq 2 2 100
14 do
15 a=$(($a+$i))
16 done
17 echo $a
18 else
19 echo "Usage:<J|O>"
20 fi

1 read -p "请输入J或者O:" num
2 a=0
3 case $num in
4 J |j)
42/81
5 for i in seq 1 2 100
6 do
7 a=$(($a+$i))
8 done
9 echo $a
10 ;;
11 O |o)
12 for i in seq 2 2 100
13 do
14 a=$(($a+$i))
15 done
16 echo $a
17 ;;
18 )
19 echo "Usage:<J|O>"
10.写一个脚本,使用case和函数现实,能够对/etc/目录进行打包,打包后存储到/backup目录下并命名为
etc年-月-日.bak的格式
显示如下菜单给用户:
xz) xz compress
gzip) gzip compress
bzip2) bzip2 compress
根据用户指定的压缩工具使用tar进行打包压缩,输入错误就提示给用户一个帮助信息,帮助信息为“脚本
名 Usage:<xz|gzip|bzip2>”
1 #!/bin/bash
2 #
3 echo "压缩方式有以下三种:"
4 echo -e "\txz)xz compress"
5 echo -e "\tgzip) gzip compress"
6 echo -e "\tbzip2) bzip2 compress"
7
8 name=etc
date +%F.bak.tar
9 xz() {
10 tar cJf /backup/$name.xz /etc &>/dev/null
11 echo "/etc目录使用xz方式归档压缩成功"
12 }
13
14 gzip() {
15 tar czf /backup/$name.gz /etc &>/dev/null
16 echo "/etc目录使用gzip方式归档压缩成功"
17 }
18
19 bzip2() {
20 tar cjf /backup/$name.bz2 /etc &>/dev/null
21 echo "/etc目录使用bzip2方式归档压缩成功"
22 }
23
24 if [ -e /backup ]
25 then
26 if [ ! -d /backup ]
27 then
28 mv /backup /backup.bak
29 mkdir /backup
30 fi
43/81
31 else
32 mkdir /backup
33 fi
34
35 read -p "请输入压缩的方式:" ys
36 case $ys in
37 xz)
38 xz
39 ;;
40 gzip)
41 gzip
42 ;;
43 bzip2)
44 bzip2
45 ;;
46
)
47 echo "$0 Usage:<xz|gzip|bzip2>"
48 esac
11.写一个脚本,显示如下菜单给用户:
cpu)print cpu information;
disk) print disk information;
mem)print memory information;
quit)quit;
Pleas enter your option:
根据用户输入的显示相应的信息,如果用户输入的不是以上几种就显示帮助信息,帮助信息为“Pleas
enter your option:<cpu|disk|mem|quit>”
1 #!/bin/bash
2 echo "可以查询的系统信息如下"
3 echo -e "\tcpu)print cpu information;"
4 echo -e "\tdisk) print disk information;"
5 echo -e "\tmem)print memory information;"
6 echo -e "\tquit)quit;"
7
8 read -p "Pleas enter your option:" ss
9 case $ss in
10 cpu)
11 cat /proc/cpuinfo
12 ;;
13 disk)
14 df -h
15 ;;
16 mem)
17 cat /proc/meminfo
18 ;;
19 quit)
20 echo "byebye"
21 ;;
22 )
23 echo "Pleas enter your option:<cpu|disk|mem| quit>"
24 esac
1 #!/bin/bash
2 echo "可以查询的系统信息如下"
3 echo -e "\tcpu)print cpu information;"
44/81
4 echo -e "\tdisk) print disk information;"
5 echo -e "\tmem)print memory information;"
6 echo -e "\tquit)quit;"
7
8 for ((i=1;i>0;i++))
9 do
10 read -p "Pleas enter your option:" ss
11 ss=echo $ss | tr "A-Z" "a-z" (将大写改为小写)
12 case $ss in
13 cpu)
14 cat /proc/cpuinfo
15 ;;
16 disk)
17 df -h
18 ;;
19 mem)
20 cat /proc/meminfo
21 ;;
22 quit)
23 exit 0
24 ;;
25
)
26 echo "Pleas enter your option:<cpu|disk|mem| quit>"
27 esac
28 done
shell脚本
shell学习目标
1.shell的特性
2.shell变量
3.shell条件测试
4.shell数值运算
5.流程、循环
6.正则表达式
7.sed
8.awk

cat ~/.vimrc

45/81
set nu
set ts=4
set ic
set ci
set si
set sw=4

shell脚本(script):
shell脚本文件:是一种linux操作命令的集合文件。用户运行脚本文件时就会自动执行文件中的命令。

入门级(初级)脚本:脚本文件中仅包含一些操作命令,无任何逻辑判断语句。这种脚本只会按从上到下的
顺序来执行命令,如果某行命令错误会自动跳过。
高级脚本:在入门级脚本的基础上加入条件判断if、循环(for、while、until)等逻辑控制语句,让脚本更具
有通用性和可移植性。
如何提高自己的脚本编写水平:经常到网上去看一些别人写的脚本,从中取经。

计算机语言分类:
解释型语言:语法没有很严格的要求,也称为弱语言(语法要求弱)。通常有shell脚本、html网页语言、
python语言、java script、VBscript、PHP、bat批处理(Windows脚本)等。脚本程序用notepad记事本、
vi/vim、notepad++等纯文本文件编辑软件来编写即可。
编译型的语言:语法要求很严格,也称为强语言。通常有C、C++、C#、Visual Basic、java、delphi等。编
译型的语言编写的源程序代码需要通过编译成计算机能够识别的二进制文件才能够运行。例如系统中的ls、
date、lsblk等命令都是用c语言编写,然后编译成命令文件,所以我们才能直接运行这个命令。这种程序的
运行效率高。
shell脚本的运行的过程:调用脚本文件中的命令--〉shell命令解释器--〉kernel内核--〉hardware
硬件
高级语言的程序运行过程:二进制程序文件--〉kernel内核--〉hardware硬件
实例:编写一个入门级的脚本文件01.sh,要实现的功能是执行clear
echo QQ:12700696、cd、ls、pwd、sleep 5s、date、lsblk命令。给01.sh添加x可执行权限,运行
01.sh脚本程序。
第1步,编写01.sh脚本文件。
mkdir /sh
vim /sh/01.sh 文件内容如下
#!/bin/bash
#date:2019-02-18
#Author By : jim
#Decription: this is my first shell script.
clear
echo QQ:12700696
cd
ls
pwd
sleep 5s
date
lsblk
46/81
第2步,添加可执行权限,运行脚本。
chmod -v +x /sh/01.sh
. /sh/01.sh 或 source /sh/01.sh 或 /sh/01.sh 或 sh /sh/01.sh 或 bash /sh/01.sh
运行脚本并显示脚本的执行过程:sh -x /sh/01.sh
技巧:
shell脚本学习的帮助文档:man bash
练习:执行如下操作,来学习bash帮助文档的使用。
man bash 分别执行如下操作,分别查看这些关键字代码的内容帮助
/if
/while
/until
/test
/&&
test
shell的条件测试
格式1:test 条件表达式
格式2:[ 条件表达式 ]
格式3:[[ 条件表达式 ]] 支持正则表达式 && ||
给x变量赋值为1314520:x=1314520
显示变量的值:echo $x
变量:变量是用来存储某个具体的值的,值可以是数值、任意字符。程序中用变量可以让程序变得更灵
活。
查上一条命令结果的状态码:echo $?
说明:$?是系统的预定义变量,是用来存上一条命令的状态码的变量。
状态码: 成功为0 失败为非0
47/81
练习:执行如下操作,了解命令结果的状态码的值。
date
echo $?
xxxxx
echo $?
ls /kkkk
echo $?
date stx
echo $?
条件判断的组合: -a -o -n
&& 逻辑与
-a
条件表达式1 && 条件表达式2
条件表达式1 -a 条件表达式2
|| 逻辑或
-o
条件表达式1 || 条件表达式2
条件表达式1 -o 条件表达式2

! 非,取反
! 条件表达式
-n 条件表达式
==文件测试===
根据文件类型判断
-e 判断文件是存在
例:
[root@client tmp]# test -e /tmp
[root@client tmp]# echo $? 存在 状态返回值为0
0
[root@client tmp]# test -e /tmpdahs 不存在 状态返回值为1
[root@client tmp]# echo $?
1
-e 判断文件名是存在
-d 判断文件是存在且是为目录文件
-f 判断文件是存在且是为普通文件
-p 判断文件是存在且是为管道文件
-b 判断文件是存在且是为块设备文件
-c 判断文件是存在且是为字符设备文件
-L 判断文件是存在且是为软链接文件
-S 判断文件是存在且是为套接字文件
根据文件权限判断
-r 判断文件是存在且是有“可读权限”
-w 判断文件是存在且是有“可写权限”
48/81
-x 判断文件是存在且是有“可执行权限”

[root@client tmp]# test -r a.a.pdf 有读权限 状态返回值为0
[root@client tmp]# echo $?
0
[root@client tmp]# test -x a.a.pdf 无执行权限 状态返回值非0
[root@client tmp]# echo $?
1
文件内容非空白的判断
-s 判断文件是存在且文件内容非空白
[root@client tmp]# test -s /etc/passwd
[root@client tmp]# echo $? 非空,有内容 状态返回值为0
0
[root@client tmp]# test -s a.pdf 为空 状态返回值非0
[root@client tmp]# echo $?
1
==数值比较===
-gt 大于
-lt 小于
-eq 等于
-ge 大于等于
-le 小于等于
-ne 不等
[root@client tmp]# test 5 -gt 3 5大于3 结果为真 状态返回码为0
[root@client tmp]# echo $?
0
[root@client tmp]# test 3 -gt 3 3大于3 结果为假 状态返回码为非0
[root@client tmp]# echo $?
1
[root@client tmp]# A=5
[root@client tmp]# B=3
[root@client tmp]# test $A -gt $B
[root@client tmp]# echo $?
0
[root@client tmp]# test $B -gt $A
[root@client tmp]# echo $?
1
==字符串比较== 字符串一定要用引号引起来
== 等值比较
= 等值比较
[root@client tmp]# A=hello
[root@client tmp]# test $A == hello 结果为真 返回值0
[root@client tmp]# echo $?
0
[root@client tmp]# test $A == hell0 结果为假 返回值非0
[root@client tmp]# echo $?
1
49/81
!= 不等值比较
[root@client tmp]# A=hello
[root@client tmp]# test $A != hello 结果为假 返回值非0
[root@client tmp]# echo $?
1
[root@client tmp]# test $A != hell0 结果为真 返回值0
[root@client tmp]# echo $?
0
=~ 判断左侧字符串或者变量是否符合右侧的模式
-z 判断字符串是空
[root@client tmp]# unset A
[root@client tmp]# unset B
[root@client tmp]# A=8
[root@client tmp]# test -z $A 结果为假 返回值非0
[root@client tmp]# echo $?
1
[root@client tmp]# test -z $B 结果为真 返回值0
[root@client tmp]# echo $?
0

命令的逻辑执行
命令1 && 命令2 当命令1执行成功时会执行命令2
命令1 || 命令2 当命令1执行失败时会执行命令2
例:
[ -d /etc ] && echo 目录已存在 || echo 目录不存在
[ -d /etck ] && echo 目录已存在 || echo 目录不存在
if语句
if条件语句:
3种结构:
if结构1:单条件,单分支。如果满足if后面的条件1(即条件的结果状态码为真[即为0]),就执行then后面的
语句。
if 条件1;then
command命令1
command命令2
fi
if语句的简写如下(命令的逻辑与执行):
命令1 && 命令2 等同于 if 条件1;then 命令列表;fi
50/81
例如:用if的结构1做如下测试。
x=abc;y=abc;z=123
if [ $x = $y ];then
echo yes
fi
if语句的简写如下:
[ $x = $y ] && echo yes
例如:判断系统中是否存在root用户,如果存在就提示yes。
用命令的逻辑执行来实现,方法如下:
id root && echo yes
用if语句来实现,写法如下:
id root
if [ $? -eq 0 ];then
echo yes
fi
if结构2:单条件,双分支。如果满足if后面的条件1(即条件的结果状态码为真[即为0]),就执行then后面的
语句,否则执行else后面的语句。
if 条件1;then
command命令1
command命令2
else
command命令3
command命令4
fi
if双分支的简写:
命令1 && 命令2 || 命令3
解释:命令1执行成功(状态码为0),就执行命令2,否则执行命令3.
例如:用if的结构2做如下测试。
x=abc;y=abc;z=123
if [ $x = $y ];then
echo yes
else
echo no
fi
if语句的简写如下:
[ $x = $y ] && echo yes || echo no
例如:判断系统中是否存在/zk目录,如果存在就删除此目录且显示过程,否则创建此目录且显示过程
方法一:用命令的逻辑执行方法来实现的写法。
[ -d /zk ] && rm -rfv /zk || mkdir -pv /zk
方法二:用if语句实现的写法。
if [ -d /zk ];then
rm -rfv /zk
else
mkdir -pv /zk
fi
51/81
例如:判断系统中是否存在zk用户,如果存在就用userdel -r zk删除此用户,否则创建zk用户。
方法一:用命令的逻辑执行方法来实现的写法。
id zk && userdel -r zk || useradd zk
方法二:用if语句实现的写法。
if id zk;then
userdel -r zk
else
useradd zk
fi
if结构3:多条件,双分支。如果满足if后面的条件1(即条件的结果状态码为真[即为0]),就执行then后面的
语句;否则测试elif后的条件2,满足条件2就执行elif的then后面的语句;否则执行else后面的语句。
if 条件1;then
command命令1
command命令2
elif 条件2;then
command命令3
command命令4
else
command命令5
command命令6
fi
例如:用if的结构3做如下测试。做猜数字游戏。
x=123
if [ $x -eq 123 ];then
echo 'you are right.'
elif [ $x -gt 123 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
例如:写一个名称为/sh/cai.sh的脚本,要求提示用户输入数字,判断数字大小是否为520,如果是就提示
yes;如果大于520,就提示bigger;否则提示little。
第1步,编写/sh/cai.sh脚本文件。
mkdir -pv /sh
vim /sh/cai.sh
#!/bin/bash
#description:this is crossword games.
read -p 'Please input your number:' x
if [ $x -eq 123 ];then
echo 'you are right.'
elif [ $x -gt 123 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
第2步,添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/cai.sh
. /sh/cai.sh
52/81
shell test及案例
bash shell的帮助手册:man bash
-gt大于 -ge大于或等于 -eq等于
-lt小于 -le小于或等于 -ne不等于
test 条件 语句 或 [ 条件 ]
功能:用来判断文件、权限、值(数值是否相等、是否为空)。
帮助手册:man test
test练习:
项目一:字符串的长度、值的判断测试。
练习:判断字符串长度为0则为真(true,状态码为0)
[root@node11 ~]# x=''
[root@node11 ~]# test -z $x
[root@node11 ~]# echo $?
0
练习:判断字符串长度不为0则为真(true,状态码为0)
[root@node11 ~]# x=1234
[root@node11 ~]# test -n $x
[root@node11 ~]# echo $?
0
练习:判断字符串内容相等为真(true,状态码为0)
[root@node11 ~]# test abc = abc
[root@node11 ~]# echo $?
0
[root@node11 ~]# test abc = abcde
[root@node11 ~]# echo $?
1
练习:判断字符串内容不相等为真(true,状态码为0)
[root@node11 ~]# test abc != abcde
[root@node11 ~]# echo $?
0
项目二:整数值的大小(相等eq、不相等ne、大于gt、小于lt、大于或等于ge、小于或等于le)判断测试。
练习:执行如下操作,熟悉整数值的大小判断测试。
x=1314
y=520
z=520
test $x -eq $y
echo $?
test $z -eq $y
echo $?
test $x -ne $y
53/81
echo $?
test $x -gt $y
echo $?
test $x -lt $y
echo $?
test $z -lt $x 520 < 1314
echo $?
test $x -ge $y 1314 >= 520
echo $?
test $z -ge $y 520 >= 520
echo $?
test $y -le $x 520 <= 1314
echo $?
test $y -le $z 520 <= 520
echo $?
项目三:文件类型(目录d、普通文件-、字符设备c、块设备b、软链接l、管道p、套接字s)、文件大小(大小
为0、不为0)、文件的新旧、权限(ugo、rwx、facl、3种s权限等)的判断测试。
[ -d /etc ]
echo $?
[ -f /etc/hosts ]
echo $?
[ -c /dev/tty ]
echo $?
[ -b /dev/sda ]
echo $?
[ -L /etc/rc.local ]
echo $?
find / -type p 在根目录及其子目录中查找类型为管道的文件
[ -p /run/dmeventd-client ]
echo $?
find / -type s
[ -S /run/systemd/notify ]
echo $?
文件权限:判断当前用户对文件是否有可读、可写、可执行权限。-r、 -w、 -x
useradd ak
su - ak
pwd
touch a1
chmod -v 0 a1
[ -r a1 ] ; echo $?
chmod -v u+r a1
[ -r a1 ] ; echo $?
[ -w a1 ] ; echo $?
[ -x a1 ] ; echo $?
touch a2
[ -t 1 ] ; echo $? 文件描述符(FD,文件在内存中的数字代号)已在终端打开了
[ -t 168 ] ; echo $?
54/81
exit
复合条件判断测试:逻辑非、逻辑与、逻辑或
[ ! abc = abcde ] ; echo $? 逻辑非
[ abc = abc -a 123 -eq 123 ] ; echo $? 逻辑与,同时满足两个条件就为真(状态码为0)
[ abc = abcd -o 123 -eq 123 ] ; echo $? 逻辑或,满足其中一个条件就为真(状态码为0)

引号
单引号:单引号中的所有字符均作为普通字符处理(即原样输出),即无法调用变量的值。
双引号:双引号中会自动识别特殊字符,即自动识别调用变量的值,如$、\n换行符、\t tab键、\r回车符
等特殊字符。
例:执行如下操作,理解单引号、双引号的区别。
x=123abc 分别看以下命令输出的结果有什么不同
echo $x
echo '$x'
echo "$x"
echo -e '${x}_\n_welcome\tlinux'
echo -e "${x}
\n_welcome\t_linux"
说明:echo 的-e 选项是允许识别\n换行符、\t tab键、\r回车符特殊字符。

说明:${x}通常等同于$x,那么什么时候需要将变量名用{}大括号括起来呢?
答:当变量名后面紧贴着其他字符时,为了避免歧义,就需要将变量名用{}大括号括起来。
例:执行如下操作,分别看输出结果有何不同。以此来理解变量名为何需要用{}大括号括起来。
x=123abc
xy=456
echo $x
echo $xy
echo $xy_haha 跟下一条命令对比结果
echo ${xy}haha 跟上一条命令对比结果
echo $x
$xy 跟下一条命令对比结果
echo ${x}_$xy 跟上一条命令对比结果
echo ${x}y
循环语句
for语句
55/81
for语句:
功能:在满足条件的情况下,重复执行某些命令操作。
for语句结构:
for i in 值1 值2 ... 值n
do
命令列表
done
例:编写一个名称为/sh/mk.sh的脚本,要求批量创建/test/a1~/test/a5这些目录,同时显示目录创建的执
行过程。
第1步,编写脚本文件。
vim /sh/mk.sh 脚本内容如下
#!/bin/bash
#description: this is a mkdir script.
for i in {1..5}
do
mkdir -pv /test/a$i
done
第2步,给脚本添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/mk.sh
. /sh/mk.sh
例:编写一个名称为/sh/user.sh的脚本,要求批量创建用户u1~u5,并且在创建用户之后查用户的id号,并
且给每个用户设置初始登录密码为007。
第1步,编写脚本文件。
vim /sh/user.sh 脚本内容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
done
第2步,给脚本添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/user.sh
. /sh/user.sh
第3步,对入门级的脚本进行如下优化。
1.在useradd创建用户之前,判断此用户是否存在,如果存在就提示user exsits,否则创建此用户并设置初
始登录密码为007.
cp -av /sh/user.sh /sh/user-new.sh
vim /sh/user-new.sh 脚本内容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
if (id u$i);then
echo "u$i user exsits."
else
56/81
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
fi
done
第4步,测试新脚本的运行。
. /sh/user-new.sh
while语句
while功能:whatis while,得到的官方解释“在条件满足时重复的执行脚本中while的do和done之间的循
环体命令”。
简单解释:当满足条件时,就进入循环。
while语法:
while 条件测试
do
cmd_list循环体
done
=======当条件测试成立(条件测试为真),执行循环体
符合条件将一直循环
直到不符合条件(条件测试为假)停止循环
练习:在命令行中执行以下操作,实现输出10以内的正整数。
i=1
while [ $i -le 10 ]
do
echo $i
let i++ 或 $[i++] 或 $((i++))
sleep 1s 等待1秒(停顿1秒)
done

例:编写一个名称为/sh/while_user.sh的脚本,要求用while循环语句,批量创建用户w1~w5,并且在创建
用户之后查用户的id号,并且给每个用户设置初始登录密码为007。
第1步,编写脚本文件。
vim /sh/while_user.sh
i=1
while [ $i -le 5 ]
do
useradd w$i && echo "w$i user added." || echo "w$i user exsits."
id w$i
echo 007 | passwd --stdin w$i
let i++
sleep 1s
done
第2步,给脚本添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/while_user.sh
. /sh/while_user.sh
57/81
思考:编写一个名称为/sh/del_users.sh的脚本,要求用while循环语句,批量查询用户w1~w5的id信息,然
后用userdel -r删除这些用户。
第1步,编写脚本文件。
vim /sh/del_user.sh
i=1
while [ $i -le 5 ]
do
id w$i
userdel -r w$i && echo "w$i user removed." || echo "w$i user not exsits."
let i++
sleep 1s
done
第2步,给脚本添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/del_user.sh
. /sh/del_user.sh

while死循环(无限循环):
while :
do
cmd_list循环体
done
例:执行如下while死循环语句,实现每隔2秒输出echo命令的中的文本内容。[按ctrl+c强制终止死循环]
while :
do
echo 'I love you!'
sleep 2s
done

例:写一个名称为/sh/cai.sh的脚本,要求用while循环控制语句,当用户猜的数字错了就连续重复猜(即提示
用户"'Please input your number"),提示用户输入数字,判断数字大小是否为520,如果是就提示yes;
如果大于520,就提示bigger;否则提示little。
第1步,编写/sh/cai-2.sh脚本文件。
mkdir -pv /sh
vim /sh/cai-2.sh
#!/bin/bash
#description:this is crossword games.
x=0
while [ $x -ne 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
第2步,添加x可执行权限,测试脚本的运行。
58/81
chmod -v +x /sh/cai-2.sh
. /sh/cai-2.sh
until
until功能:直到条件满足时,就停止循环。
语法:
until 条件测试
do
循环体
done
=======当条件测试成立(条件测试为假),执行循环体
不符合条件将一直循环
直到符合条件(条件测试为真)停止循环
例:在命令行中执行如下操作,实现用until循环来输出1~10这些数。
i=1
until [ $i -gt 10 ]
do
echo $i
let i++
done
思考:将while语句的猜字游戏脚本/sh/cai-2.sh进行改写,用until语句来实现。
第1步,编写/sh/cai-3.sh脚本文件。
mkdir -pv /sh
vim /sh/cai-3.sh
#!/bin/bash
#description:this is crossword games.
x=0
until [ $x -eq 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
第2步,添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/cai-3.sh
. /sh/cai-3.sh
59/81
循环实例
循环实例:
1.用for输出1~100的求和结果。
2.用for语句输出等腰直角三角形。
3.用for语句输出九九乘法口诀表。
4.用for语句实现批量创建用户、查用户id号、设置用户初始密码。
例1:编写一个名称为/sh/100jia.sh的脚本,要用for进行循环控制,实现输出1+2+...+100的计算结果。
echo '#!/bin/bash
sum=0
for ((i=0;i<=100;i++))
do
sum=$[i+sum]
done
echo $sum
' > /sh/100jia.sh
chmod -v +x /sh/100jia.sh
. /sh/100jia.sh
例3:编写一个名称为/sh/3ja.sh的脚本,用for进行循环控制,实现在屏幕上显示一个5行由号组成的等腰
直角三角形。

**




解题思路:外层for循环控制三角形中星号的行数,内层for循环控制三角形中星号的列数。
echo '#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=5;j>=i;j--))
do
echo -n ""
done
echo
done
' > /sh/3ja.sh
chmod -v +x /sh/3ja.sh
. /sh/3ja.sh
循环分析:for循环中每次i、j变量的取值分析。
第一次循环:
60/81
i=1 j=1
换行
第二次循环:
i=2 j=1
i=2 j=2 **换行
第二次循环:
i=3 j=1
i=3 j=2
i=3 j=3 **换行
第四、五次循环依次类推。
例4:编写一个名称为/sh/3jb.sh的脚本,用for进行循环控制,实现在屏幕上显示一个5行由
号组成的等腰
直角三角形。




*

echo '#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=5;j>=i;j--))
do
echo -n ""
done
echo
done
' > /sh/3jb.sh
chmod -v +x /sh/3jb.sh
. /sh/3jb.sh
例4:编写一个名称为/sh/99.sh的脚本,用for进行循环控制,实现在屏幕上显示'九九乘法表口诀'。
1X1=1
1X2=2 2X2=4
1X3=3 2X3=6 3X3=9
……
61/81
1X9=9 2X9=18 …… 9X9=81
echo '#!/bin/bash
for ((i=1;i<=9;i++))
do
for ((j=1;j<=i;j++))
do
echo -ne "${j}X${i}=$[i
j]\t"
done
echo
done
' > /sh/99.sh
chmod -v +x /sh/99.sh
. /sh/99.sh
case语句
case功能:根据变量的取值不同,执行不同的命令操作。
case语句结构:
read -p 'please input your choice:' 变量名
case $变量名 in
值1)
命令1
命令2
;;
值2)
命令3
命令4
;;
)
命令5
命令6
;;
esac
例:编写一个名称为/sh/menu.sh的脚本,要求显示一个主菜单界面,提示用户输入功能选项,回车确认后
执行指定选项的命令操作。
第1步,根据项目需求,编写出脚本内容。
vim /sh/menu.sh 入门级脚本内容如下:
echo '---------------------
62/81
1/a.Install NFS Service
2/b.Install Vsftpd Service
3/c.Install Samba Service
4/d.Install DNS Service
5/e.Install Apache Service
6/f.Install PXE Service
7/g.Install DHCP Service
0/
.Exit Shell Script
---------------------'
read -p 'please input your choice:' opt
case $opt in
1|a)
echo 'Install NFS Service'
. /sh/nfs-new.sh
;;
2|b)
echo 'Install Vsftpd Service'
. /sh/ftp-new.sh
;;
0|)
echo 'Exit Shell Script'
#exit 0
;;
esac
第2步,给脚本添加x可执行权限,测试脚本的运行。
chmod -v +x /sh/menu.sh
. /sh/menu.sh
63/81
模式匹配case
功能:根据用户输入的功能选项,执行对应功能选项的任务。
case的语法结构
case 变量 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
模式3)
命令序列3
;;

无匹配后的命令序列
esac
5.交互式脚本
需求:提示用户输入功能选项,选项1为执行clear、date、创建jack用户、设置jack密码功能;选项2为执
行clear、删除jack用户;如果输入其他字符则提示“未输入正确的功能选项,程序退出”,且自动退出脚
本。
64/81
vi case1.sh 代码内容如下
#!/bin/bash
read -p "请输入功能选项数字代号,如1、2...:" choice
case $choice in
1)
clear
date
useradd jack
echo jack | passwd --stdin jack
;;
2)
clear
id jack && userdel -r jack || echo "jack用户不存在"
;;
)
echo "未输入正确的功能选项,程序退出"
exit 1
esac
6.脚本中交互式实现
判断用户输入的字符串,
如果用户输入的字符串为start,就在/tmp下创建一个start文件;
如果用户输入的为stop,那么就删除/tmp/start文件;
如果用户输入的为restart,那么就先删除/tmp/start文件,然后创建一个start1文件;
如果用户输入其他的字符串,就输出一个帮助信息:脚本名 Usage:{start|stop|restart}
read -p "请输入字符串:" strings
case $strings in
start)
touch /tmp/start
;;
stop)
rm -rf /tmp/start
;;
restart)
if [ -e /tmp/start ]
then
rm -rf /tmp/start
else
touch /tmp/start1
fi
;;

echo "$0 Usage:{start|stop|restart}"
esac
1.超市卖水果
你输入苹果,显示 苹果 5元每斤
你输入香蕉 ,显示 香蕉 3元每斤
你输入橘子,显示 橘子 3元每斤
如果你输入的不是苹果 香蕉 橘子 就提示只能查询 苹果 香蕉 橘子
#!/bin/bash 可以把红色的分别换成0,1,2或者apple|0),banana|1),orange|2)
read -p "输入要查询价格的水果名:" aa
65/81
case $aa in
apple)
echo "apple 5元每斤";;
banana)
echo "banana 3元每斤";;
orange)
echo "orange 3元每斤";;
)
echo "Usage :{apple|banana|orange}"
esac
11.写一个脚本,显示如下菜单给用户:
cpu)print cpu information;
disk) print disk information;
mem)print memory information;
quit)quit;
Pleas enter your option:
根据用户输入的显示相应的信息,如果用户输入的不是以上几种就显示帮助信息,帮助信息为“Pleas
enter your option:<cpu|disk|mem|quit>”
1 #!/bin/bash
2 echo "可以查询的系统信息如下"
3 echo -e "\tcpu)print cpu information;"
4 echo -e "\tdisk) print disk information;"
5 echo -e "\tmem)print memory information;"
6 echo -e "\tquit)quit;"
7
8 read -p "Pleas enter your option:" ss
9 case $ss in
10 cpu)
11 cat /proc/cpuinfo
12 ;;
13 disk)
14 df -h
15 ;;
16 mem)
17 cat /proc/meminfo
18 ;;
19 quit)
20 echo "byebye"
21 ;;
22
)
23 echo "Pleas enter your option:<cpu|disk|mem| quit>"
24 esac
66/81
技术回顾
test 检测、判断命令
test作用:检测文件类型和比较值。
检测文件类型:
-e FILE 文件名存在就为真
-f FILE 文件名存在且为普通文件就为真
-d FILE 文件名存在且为目录就为真
-b FILE 文件名存在且为block块设备文件就为真
-S FILE 文件名存在且为Socket套接字文件就为真
-L FILE 文件名存在且为symbolic link 符号链接(即快捷方式)文件就为真
-c FILE 文件名存在且为char字符设备文件就为真
-p FILE 文件名存在且为pipe管道文件就为真
检测文件权限:
-r FILE 当前用户对此文件可读就为真
-w FILE 当前用户对此文件可写就为真
-x FILE 当前用户对此文件可执行就为真
文件新旧检测:
FILE1 -ef FILE2 文件1和文件2有相同的设备和inode索引号就为真
FILE1 -nt FILE2 文件1的mtime新于(newer than)文件2就为真
FILE1 -ot FILE2 文件1的mtime旧于(older than)文件2就为真
逻辑与、或、非:
! EXPRESSION 非,EXPRESSION表达式的值(状态码)取反,状态码0的取反值为1
EXPRESSION1 -a EXPRESSION2 逻辑与,-a左右两边表达式的值都为真就为真
EXPRESSION1 -o EXPRESSION2 逻辑或,-o左右两边表达式的值一个为真就为真
字符串检测:
string1 = string2 字符串内容相同就为真(状态码为0)
string1 != string2 字符串内容不相同就为真(状态码为0)
-z string1 字符串长度为0就为真(状态码为0)
-n string1 字符串长度不为0就为真(状态码为0)
整数检测:
int1 -eq int2 相等(equal)
int1 -ne int2 不相等(no equal)
int1 -gt int2 大于(greater than)
int1 -ge int2 大于或等于(greater or equal than)
int1 -lt int2 小于(less than)
int1 -le int2 小于或等于(less or equal than)

if语句:
结构1:if单分支
if 条件;then
cmd_list
67/81
fi
结构2:if双分支
if 条件;then
cmd_list1
else
cmd_list2
fi
结构3:if多分支
if 条件1;then
cmd_list1
elif 条件2;then
cmd_list2
else
cmd_list3
fi

for循环语句:
for结构1:shell脚本专用的语法结构
for i in value1 value2 value3
do
cmd_list
echo $i
done
例:l为矩形的长,其值固定为2,i为矩形的宽,其值为2~6,用for循环来计算矩形的面积s,输出s的值。
方法一:用$[公式]来实现计算。
l=2
for i in 2 3 4 5 6; do s=$[li]; echo $s; done
方法一:用$((公式))来实现计算。
l=2
for i in 2 3 4 5 6; do s=$((l
i)); echo $s; done

for结构2:C语言和shell脚本通用的语法结构
for ((i=0;i<=6;i++)) 说明:i++是i=i+1的简写,i=i+2可写成i+=2
do
cmd_list
echo $i
done
函数
函数

完成特定功能的代码段(块)
68/81
在shell中定义函数可以使用代码模块化,便于复用(即重复使用)代码
函数必须先定义才可以使用
一、定义函数
方法一:
函数名() {
函数要实现的功能代码
}
方法二:
function 函数名 {
函数要实现的功能代码
}
a=789
[root@node11 ~]# function a {

echo $a
}
a
例:查看functions、network服务的控制脚本文件内容,其中就有函数。
cat -n /etc/rc.d/init.d/functions | more
cat -n /etc/rc.d/init.d/network | more
二、函数的调用
函数名
1.函数外的参数能被函数调用
#!/bin/bash
a=123
num_1() {
echo $a
}
num_1
2.函数内的参数也能被函数调用
#!/bin/bash
num_2() {
a=456
}
num_2
echo $a
3.使用local来隔离变量,
使参数只能在函数内调用
vim /sh/f.sh
#!/bin/bash
a=love
num_3() {
local a=789
echo "in num_3"
echo $a
69/81
}
num_3
echo "out of num_3"
echo $a
[root@today tmp]# bash /sh/f.sh
in num_3
789
out of num_3
love

项目案例:以下是centos 6系统的服务管理(start启动、stop停止、restart重启、reload平滑重启、status
状态)脚本的基本框架参考代码。
#!/bin/bash
#
start() {
touch /tmp/start
}
stop() {
rm -rf /tmp/start
}
read -p "请输入字符串:" strings
if [ $strings == "start" ]
then
start
elif [ $strings == "stop" ]
then
stop
elif [ $strings == "restart" ]
then
stop
start
else
echo "$0 Usage:{start|stop|restart}"
fi
作业
练习:编写一个名称为/sh/admin.sh的脚本,要求综合实现如下功能:
1.clear清屏,显示'admin menu'功能菜单。admin menu菜单内容如下:
-----admin menu-----

  1. install NFS
  2. install Vsftpd
  3. Install Samba
  4. Install httpd
  5. Install DHCP
    70/81
  6. Install PXE
  7. Stop Firewalld and Selinux
  8. Configuration Local Yum
  9. add Users
  10. Install DNS

    2.提示用户"输入功能选项的数字编号"。
    3.用case语句取判断用户输入的功能选项,来执行功能选项所对应的操作命令。
    4.需要将admin menu菜单中的每个功能定义成函数,在case语句中调用不同的函数。
    vim /sh/admin.sh 脚本内容如下
    #!/bin/bash
    echo '-----admin menu-----
    1.install NFS
    2.install Vsftpd
    3.install Samba
    4.install Httpd
    5.install DHCP
    6.install PXE
    7.Stop Firewalls and Selinux
    8.Configuration Local Yum
    9.add Users
    10.Instsall DNS
    -----------------------'
    _NFS(){
    soft='nfs-utils rpcbind'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _Vsftpd(){
    soft='vsftpd lftp ftp'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _Samba(){ soft='samba samba-comment samba-client'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _Httpd(){ soft='Httpd'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _DHCP(){ soft='dhcpd'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _PXE(){ soft='vsftpd dhcpd tftp-server '
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _firewalld(){
    systemctl stop firewalld
    getenforce
    }
    _yum(){ [ -d /iso ] && echo '/iso is exists' || mkdir -pv /iso
    lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso
    cd /etc/yum.repos.d
    [ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak
    71/81
    mv -fv .repo bak
    echo '[centos7.6]
    name=centos 7.6 linux
    baseurl=file:///iso
    enabled=1
    gpgcheck=0
    ' >/etc/yum.repos.d/iso.repo
    yum clean all
    yum repolist
    }
    _addusers(){ i=wl
    id $i && echo 'user is exists' || useradd $i
    }
    _DNS(){ soft='bind bind-utils'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    read -p '输入功能选项的数字编号:' i
    case $i in
    1)
    _NFS
    ;;
    2)
    _Vsftpd
    ;;
    3)
    _Samba
    ;;
    4)
    _Httpd
    ;;
    5)
    _DHCP
    ;;
    6)_PXE
    ;;
    7)_firewalld
    ;;
    8)_yum
    ;;
    9)_addusers
    ;;
    10)_DNS
    ;;
    )
    echo 'input error shell.exit'
    ;;
    esac
    算术运算
    72/81
    1.整数运算
    方法一:expr

    expr 1 + 2

    3
    [root@client tmp]# A=156
    [root@client tmp]# B=456
    [root@client tmp]# expr $A + $B
    612
    +

    *
    /
    % 取模(取余数),取除法运算后的余数。例:expr 7 % 2
    方法二:$(()) + - / %
    [root@client tmp]# echo $((6
    9))
    54
    [root@client tmp]# echo $(((9-6)9))
    27
    [root@client tmp]# echo $((31%2))
    1
    [root@client tmp]# sum=$((6
    9));echo $sum
    54
    方法三:$[] + - * / %
    [root@client tmp]# echo $[456+789]
    1245
    方法四:let
    let
    [root@client tmp]# let num2=9+25 ;echo $num2
    34
    说明:let命令中,要想输出表达式的计算结果,必须把表达的结果赋值给一个变量,然后用echo 输出这
    个变量的值。
    Linux计算器:

    bc //交互式操作

    9/2
    4
    scale=2 //指定精度,精度就是小数点后保留几位小数
    9/2
    4.50
    ctrl d 退出
    非交互式操作
    [root@client tmp]# echo "0.36+356" | bc
    356.36
    [root@client tmp]# echo "scale=6;10/3" |bc
    3.333333
    进制之间的转换
    73/81
    [root@client tmp]# echo "ibase=2;11111111" | bc //将二进制数转成十进制数
    255
    [root@client tmp]# echo "ibase=10;obase=16;11" | bc //将十进制数转成16进制数
    B
    说明:十六进制数由0~9、A~F这十六个元素组成。
    [root@client tmp]# echo "ibase=10;obase=2;255" | bc /将十进制数转成二进制数
    11111111
    附录:2的幂
    2的幂: 10 9 8 7 6 5 4 3 2 1 0
    十进制: 1024 512 256 128 64 32 16 8 4 2 1

数组
数值:
赋值100个变量,这样要起100个变量名,数组的话使用1个名称就可以了,后跟100个值,在访
问值的时候要使用下标的方式

声明:
declare -a 数组名 声明变量为数组类型
declare -i 变量名 声明变量为整数数字类型
[root@client tmp]# num=6+5
[root@client tmp]# echo $num
6+5
[root@client tmp]# declare -i num=6+5
[root@client tmp]# echo $num
11

declare -x 变量名 声明变量为环境变量 用法和export一样
declare -r 变量名 声明变量为readonly类型,只读类型,变量的内容不可改

declare -a array

declare -a array1

定义数组: 变量值称为数组的元数
方法一:一次赋一个值
数组名[下标]=值

array[0]=apple

array[1]=orange

array[2]=banana

方法二:一次赋多个值
数组名=(值1 值2 值3 ...)

array1=(tom jim jack)

查看数组
74/81

declare -a |grep arr

declare -a array='([0]="apple" [1]="orange" [2]="banana")'
declare -a array1='([0]="tom" [1]="jim" [2]="jack")'

访问数组元数:

echo ${array[0]} 访问数组中的第一个元数

apple

echo ${array[*]} 访问数组中的所有元数 数组的遍历

echo ${array[@]}

echo ${#array[@]} 统计数组元数的个数

echo ${#array[*]}

echo ${!array[@]} 获取数组元数的索引

0 1 2

echo ${array[@]:1} 从数组下标1开始

orange banana

echo ${array[@]:1:2} 从数组下标1开始,访问2个元数

orange banana

declare -a | grep name

declare -a name='([0]="user1" [1]="user2" [2]="user3" [3]="user4" [4]="user5" [5]="user6")'
[root@client ~]# echo ${name[@]}
user1 user2 user3 user4 user5 user6

user2 user3 user4 user5 user6

user4 user5 user6

user3 user4 user5
取消数组
#unset 数组名

echo ${name[@]}

user1 user2 user3 user4 user5 user6

for i in ${name[@]};do echo $i ;done

user1
user2
user3
user4
user5
user6
1.超市卖水果
你输入苹果,显示 苹果 5元每斤
你输入香蕉 ,显示 香蕉 3元每斤
你输入橘子,显示 橘子 3元每斤
如果你输入的不是苹果 香蕉 橘子 就提示只能查询 苹果 香蕉 橘子
vim /sh/fruit.sh 脚本内容如下:
#!/bin/bash
declare -a num
num=(apple banana orange)
read -p "输入要查询价格的水果名:" aa
if [ $aa == ${num[0]} ] ; then
75/81
echo "$aa 5元一斤"
elif [ $aa == ${num[1]} ] ; then
echo "$aa 3元一斤"
elif [ $aa == ${num[2]} ] ; then
echo "$aa 3元一斤"
else
echo "Usage :{apple|banana|orange}"
fi
case语句
#!/bin/bash
declare -a num
num=(apple banana orange)
read -p "input your fruits:" aa
case $aa in
0)
echo "apple 5元一斤"
;;
1)
echo "banana 3元一斤"
;;
2)
echo "orange 2元一斤"
;;
*)
echo "usage:{apple|banana|orange}"
;;
esac
~
例子:双色球×××
red红球: 33选6
blue蓝球: 16选1

echo $RANDOM 输出一个随机数

echo $[$RANDOM%33+1]

echo $[$RANDOM%16+1]

最简单的×××,但是红球有可能重复
vim /sh/cp.sh 脚本内容如下
#!/bin/bash
for i in {1..6}
do
red[$i]=$[$RANDOM%33+1]
echo -ne "${red[$i]}\t"
done
echo
echo "$[$RANDOM%16+1]"
如何去除红球的重复?
i=1
while [ $i -le 6 ]
do
redtmp=$[$RANDOM%33+1]
flag="yes"
for j in ${red[*]}
76/81
do
if [ $j -eq $redtmp ]
then
flag="no"
break
fi
done
if [ $flag = "yes" ]
then
red[$i]=$redtmp
let i++
fi
done
for i in {1..6}
do
echo -n "${red[i]} "
done
echo
echo "$[$RANDOM%16+1]"

正则表达式
正则表达式(正确的规则表达式):是用来做关键字匹配的。它是一种字符模式,是在匹配文本时,使用一
些特殊的符号,匹配用户想要的东西
正则表达式、通配符的区别:应用场合不同
通配符:是用在查找文件名时或?或[关键字]来匹配文件名中不确定的字符。ls /dev/tty[135]?
正则表达式:是用在查看文件内容时^、$、+、
、?、[]、.等符号来匹配文件内容中不确定的字符。
字符模式:
普通字符:没有特殊含义的字符 a b c
元字符:具有特殊含义的字符 ^ $ . []
shell元字符:
通配符 由shell来解析,Shell将解析为任意多个字符
正则表达式元字符:
前导符 由各种执行模式匹配操作的程序来解析,比如vim(查找和替换)、
grep、egrep、sed、awk

何时用?
能够使用正则表达式的命令:vim(查找和替换)、grep、sed、awk
匹配数字:^[0-9]+$ 例:echo -e '123\n456\n7s9' | egrep '^[0-9]+$' 输出结果:123 456
匹配Mail:[a-z0-9]+@[a-z0-9]+.[a-z]+ 数字和字母@数字和字母.com xiaoming123@163.com
例:echo -e '12@qq.com\nfly@163.com\n58.com' | egrep '[a-z0-9]+@[a-z0-9]+.[a-z]+'
匹配ip地址:[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3} 例:1.2.3.4
77/81
[0-9]
[0-9][0-9]
[0-9][0-9][0-9]
例: echo -e '192.168.11.11\n172.16.5.3\na.b.c.d\n127.0.0.1' | egrep '[0-9]{1,3}.[0-9]{1,3}.
[0-9]{1,3}.[0-9]{1,3}'

例:编写一个名称为/sh/zhz.sh的脚本,要求提示用户输入一个数字,判断用户输入的是否是数字,如果是
就提示'yes',否则提示'no'。
vim /sh/zhz.sh
#!/bin/bash
read -p 'input a number:' x
echo $x | egrep -q '^[0-9]+$'
if [ $? -eq 0 ];then
echo 'yes'
else
echo 'no'
fi

[root@client ~]# grep "abc" /etc/passwd --color
abrt:x:173:173::/etc/abrt:/sbin/nologin
[root@client ~]# grep "roo
" /etc/passwd --color
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
rtkit:x:499:497:RealtimeKit:/proc:/sbin/nologin
基本正则表达式元字符
元字符 功能 例子 匹配结果
字符的匹配 . 匹配任意单个字符 /l.ve/ 匹配love、live...
[] 匹配一组字符中的任意一个 /l[Oo]ve/ 匹配love、lOve
[x-z] 表示匹配一段范围中的任意一个 /l[a-c]ve/ 匹配lave、lbve、lcve
"^[a-Z0-9]+" 大小写字母或数字
[0-9] 数字
[a-z] 小写字母
[A-Z] 大写字母
[0-9a-z] 小写字母或数字
[^] 表示取反 /[^a-c]ove/ 匹配除了aove、bove、
cove以外的字符
次数的匹配
前导符(即号左边的字符) 匹配号左边的字符0个或多个 /lve/ 匹配
ve、lve、llve、lllllllllve...
x{m} 匹配x出现m次。 x是字符或字符串,m是一个数字 /a{3}/ 匹配到aaa
x{m,} 匹配x出现至少m次 /a{2,}/ 匹配到aa、aaa、aaaa...
x{m,n} 匹配x出现m次到n次 /a{2,4}/ 匹配到aa、aaa、aaaa
x{0,n} 匹配x出现最多n次 /a{0,3}/ 匹配到a、aa、aaa
位置的定位 ^ 行首定位符 /^root/ 匹配以root开头的行
$ 行尾定位符 /bash$/ 匹配以bash结尾的行
\< 词首定位符 /\<love/ 匹配到lovely、lover等.例:echo -e 'lovely
\nalove\nlover' | grep '\<love'
\> 词尾定位符 /love\>/ 匹配到inlove等 .例:echo -e 'klove\inalove
\nlover' | grep 'love\>'
\b /love\b/
78/81
\ 用来转义(将字符在普通意义和特殊意义之间转换)元字符 /2.5/ 匹
配2.5
分组
(..) 将括号内的内容作为一个单位来看(并且在内存中会用1~n记录这些值),内容
可以是字串也可以是一个模式 (love)\1er 匹配loveloveer
# 引用前面第#个“(”和与之对应的“)”中的模式所匹配到的内容,#至少为1
(ab)(ac)(dd) abacddacddab
(ab)(ac)(dd).
\2\3\1 abacddjjjacddab

:1,$ s/(192.168.1).20/\1.50/g 将.20替换成.50
:3,9 s/(.*)/#\1/ 匹配任意一个字符开头加上#
:%s/172.16.1.1/172.16.1.5/ 将172.16.1.1替换成172.16.1.5
:% s/(172.16.1.)1/\15/ 172.16.1.
:% s/(172.)(16.)(1.)1/\1\2\35/g 172.16.1.1 172.16.1.5

正则表达式的组合:
.* :任意字符任意次 匹配0到多个任意字符
^$:匹配空白行
扩展正则表达式元字符
元字符 功能 例子 匹配结果
? 表示0个或1个它前面的字符 a?d ad d aad

  • 表示1个或多个它前面的字符 a+d ad d aad aaad...
    | 或者 a|b a b aa
    ()
    (..)(..)\1\2
    x{m} 前置字符x出现了m次
    x{m,}
    x{m,n}
    x{0,n}
    \d 匹配0~9数字(digital) ????????
    POSIX字符集
    表达式 功能 示例 例子 等同于
    [:alnum:] 字母和数字 [[:alnum:]]+ [a-Z0~9]
    [:alpha:] 字母(包括大小写字母) [[:alpha:]]{4}
    [:lower:] 小写字母
    [:upper:] 大写字母
    [:digit:] 数字 [[:digit:]]?
    [:blank:] 空格和制表符 [[:blank:]]
    [:punct:] 标点符号
    [:space:] 包括换行符,回车等所有空白
    grep 基本正则表达式
    grep -E 或 egrep 支持扩展表达式
    例:
    ip a | egrep '[[:alpha:]]'
    echo -e 'aaa\naaaaaa\naaaa\nccc\ncccc' | egrep '[[:alpha:]]{4}'
    79/81
    grep执行状态的返回值三种
    0 :该文件中搜索到匹配行
    1 :该文件中没有搜索到匹配行
    2 :搜索文件不存在
    思考练习:
    1.如果输入小写字母,提示输入的是小写字母
    如果输入大写字母,提示输入的是大写字母
    如果输入的是数字,提示输入的是数字
    如果输入的是其他内容,提示只能输入字母数字空白
    vim /sh/char.sh 参考内容如下
    #!/bin/bash
    read -p 'input your char:' x
    if echo "$x" | egrep -wq '[[:lower:]]
    ' ;then
    echo 'lower word.'
    elif echo "$x" | egrep -wq '[[:upper:]]' ;then
    echo 'upper word.'
    elif echo "$x" | egrep -wq '[[:digit:]]
    ' ;then
    echo 'number word.'
    else
    echo 'only input word 、 number、blank.'
    fi
    2.使用ifconfig命令查找ip地址,使用正则表达式只显示ip地址
    1~254.1~254.1~254.1~254
    1-9
    10-99
    100-199
    200-249
    250-254

    grep "\<[1-9]\>|\<[1-9][0-9]\>|\<1[0-9][0-9]\>|\<2[0-4][0-9]\>|25[0-4]" --color /tmp/

    num1.txt

    grep "\<[1-9][0-9]{0,1}\>|\<1[0-9]{2}\>|\<2[0-4][0-9]\>|25[0-4]" --color /tmp/

    num1.txt

作业

  1. 把每个数字用()括起来
    :%s/([0-9])/(\1)/g
    :%s/([[:digit:]])/(\1)/g
    80/81
  2. 匹配ip每个十进制数的范围是1~255

    grep -E "\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4])\>" /tmp/aa.txt

  3. for ping测试指定网段的主机
    网段由用户输入,例如用户输入192.168.1,则ping 192.168.1.1~192.168.1.20
    ping通的主机将主机的ip地址保存在/tmp/host_up.txt UP:/tmp/host_up.txt
    ping不通的主机将主机的ip地址保存在/tmp/host_down.txt Down:/tmp/host_down.txt
    vim /sh/ping.sh
    #!/bin/bash
    #

    /tmp/host_up.txt
    /tmp/host_down.txt
    read -p "请输入一个网段:" wd
    for ((i=1;i<=20;i++))
    do
    ( ping -c 2 -W 1 "$wd".$i > /dev/null
    if [ $? -eq 0 ];then
    echo "${wd}.${i} up" | tee -a /tmp/host_up.txt
    else
    echo "${wd}.${i} down"| tee -a /tmp/host_down.txt
    fi
    )&
    done
    4.匹配用户名是三个字符的用户
    :^[^:][^:][^:]\>

    grep "^[^:][^:][^:]>\" /tmp/test

5.删除每行的倒数第二个字符
:%s/(.)(.)$/\2/
6.搜索包含2个o的行
o+.*o+
7.显示/boot/grub/grub.conf中至少一个空白字符开头的行

grep "^[[:space:]]{1,}" /boot/grub/grub.conf

grep "^[[:space:]]+" /boot/grub/grub.conf

8.显示/etc/rc.d/rc.sysinit文件中,以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的

grep "^#[[:space:]]{1,}[^[:space:]]{1,}" /etc/rc.d/rc.sysinit

grep "^#[[:space:]]+[^[:space:]]+" /etc/rc.d/rc.sysinit

egrep "^#[[:space:]]+[^[:space:]]+" /etc/rc.d/rc.sysinit

81/81

转载于:https://blog.51cto.com/14173127/2365425

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值