第1章 shell基本概述
1.什么是shell
shell是一个命令解释器,主要用来接收用户的指令,进入驱动操作系统,或硬件。
Linux里有很多种shell,例如:
Bourne Shell(/usr/bin/sh或/bin/sh)
Bourne Again Shell(/bin/bash)
C Shell(/usr/bin/csh)
K Shell(/usr/bin/ksh)
Shell for Root(/sbin/sh)
2.什么是shell脚本
shell脚本就是把命令全部放在一起执行
shell脚本里可以包含若干个变量,循环,if判断,for循环,函数等
特定的格式+特定的语法+系统的命令 = shell脚本
3.shell可以实现什么功能
1.Linux系统支持的命令,都可以用shell实现
2.系统优化脚本,例如:优化SSH 修改端口号 配置yum源 关闭SElinux,时间同步,安装常用软件等操作
3.定时任务,例如每天定时备份数据库的数据
4.日志切割脚本,定时切割日志
5.服务启动脚本,二进制安装的服务没有systemd,可以写脚本启动
6.代码上线脚本,将开发好的代码使用脚本部署到web服务器
7.zabbix自定义监控脚本,使用脚本获取自定义的监控项的数值
8.跳板机脚本,可以使用shell开发一个跳板机
4.学习shell的必备技能
1.熟练的VIM技能
2.熟练的Linux基础命令使用
3.熟练的正则表达式和三剑客命令使用
5.学习shell的正确姿势
1.知道自己要干什么,想要什么效果
2.拿到需求先不要立刻写脚本,先用命令行实现,然后转换成脚本
3.先能看懂,然后模仿,然后会修改,最后能按照自己的需求编写各种shell脚本
4.思考,练习,总结 --> 思考,练习,总结
第2章 shell入门
1.shell书写方式
1.shell脚本名称必须要有含义,切忌随便起名,在公司里容易被打。文件后缀名最好以.sh结尾。
2.shell脚本首行建议添加使用的解释器,如:#!/bin/bash
3.最好给自己的脚本加个注释,注释内容包含了脚本创建时间,作者,以及脚本作用等。
4.注释尽量不要有中文
5.脚本放在专门的目录里
举例:
#!/bin/bash #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
# Author: Oldjie. 1043018380@qq.com #作者名称
# Create Time 2020/07/31 #创建日期
# Script Description: this is my 1st shell script. #脚本描述
2.第一个shell脚本
cat > hello.sh <<
#!/bin/bash
echo "Hello World"
EOF
3.shell执行方式
3.1 执行脚本命令
./test.sh
bash test.sh
source test.sh
3.2 首行不指定解释器
1.如果不在脚本首行指定 #!/bin/bash解释器,那么./执行的时候系统会默认调用bash来执行脚本。
2.那是如果我的脚本是python语言写的,那么执行的使用就会报错。
3.3 首行指定解释器
1.如果首行添加了解释器./执行的时候默认会读取脚本第一行,来确定使用什么解释器运行脚本。
3.4 直接指定解释器运行
我们也可以直接指定使用什么解释器来运行,那样即使脚本首行没有添加解释器也可以运行,例如
bash test.sh
python test.sh
3.5 python的hello
#!/usr/bin/python3
hello = 'hellooooo'
print(hello)
第3章 shell变量
1.什么是变量
变量是Shell传递数据的一种方式。
以一个固定的字符串去表示一个不固定的值,便于后续的复用和维护。
2.变量的分类
环境变量(全局变量) 对整个系统生效
普通变量(局部变量) 只对当前的脚本生效
变量的生存周期
永久的 需要修改环境变量配置文件 变量永久生效 /etc/profile
临时的 直接使用export声明变量即可,关闭shell则变量失效
临时变量的export区别
不加export 则只对当前的shell生效
加export 则对当前打开窗口所有的shell生效
3.环境变量配置文件生效的顺序
1.登陆Shell首先会加载/etc/profile文件
2.然后会执行家目录中的环境变量配置文件
3.按照执行顺序
/etc/profile
.bash_profile
.bashrc
/etc/bashrc
4.变量的命名规范
1.以大小写字母 下划线 数字 拼接成变量名,最好以字母开头,最好名字有含义,不然写着写着很容易忘记这个变量干嘛用的
2.变量名=变量值 等号表示给变量赋值,注意等号两边不要有空格
3.系统的环境变量都是大写的,注意不要用系统保留的变量名称,比如PATH
4.变量命名最好不要与系统命令冲突,比如 date=20200731
变量命名参考:
path_data #全小写
Path_Date #驼峰写法,首字母大写
PATH_DATA #全大写
5.变量定义的几种方式
5.1 字符串定义变量
定义一个变量:
[root@m-61 ~]# name="oldjie"
查看变量:
[root@m-61 ~]# echo "$name"
oldjie
[root@m-61 ~]# echo "${name}"
oldjie
5.2 命令定义变量
使用命令定义变量:
[root@m-61 ~]# time=`date`
[root@m-61 ~]# echo ${time}
2020年 07月 31日 星期五 19:11:17 CST
[root@m-61 ~]# time=$(date +%F)
[root@m-61 ~]# echo ${time}
2020-07-31
命令定义变量两种方式区别:
1.反引号 `命令` 和 $(命令) 都可以表示将命令赋值给变量
2.建议使用$(),因为如果脚本语句里包含单引号和双引号,很容易和反引号搞混,另外也不方便阅读。
5.3 引用变量
引用变量$和 ${}的区别:
[root@m-61 ~]# echo "$name_host"
[root@m-61 ~]# echo "${name}_host"
oldjie_host
结论:
如果不加${},可能会造成歧义,使用${}更保险
单引号和双引号区别:
[root@m-61 ~]# echo "name is ${name}"
name is oldjie
[root@m-61 ~]# echo 'name is ${name}'
name is ${name}
结论:
1.单引号不会解析变量,给什么,吐什么
2.双引号可以正确解析变量
什么情况下使用单引号和双引号:
1.如果需要解析变量,就用双引号
2.如果输出的结果要求是普通的字符串,或者需要正确显示特殊字符,则可以用单引号或者撬棍\。
6.变量的传递
6.1 位置参数传递
执行脚本的时候我们可以通过传递参数来实现变量的赋值,接受参数的变量名是shell固定的,我们不能自定义.
脚本如下:
cat > vars.sh <<'EOF'
#!/bin/bash
echo "#当前shell脚本的文件名: $0"
echo "#第1个shell脚本位置参数:$1"
echo "#第2个shell脚本位置参数:$2"
echo "#第3个shell脚本位置参数:$3"
echo "#所有传递的位置参数是: $*"
echo "#所有传递的位置参数是: $@"
echo "#总共传递的参数个数是: $#"
echo "#当前程序运行的 PID 是: $$"
echo "#上一个命令执行的返回结果: $?"
EOF
执行效果:
bash vars.sh 11 22 33 44
#当前shell脚本的文件名: vars.sh
#第1个shell脚本位置参数:11
#第2个shell脚本位置参数:22
#第3个shell脚本位置参数:33
#所有传递的位置参数是: 11 22 33 44
#所有传递的位置参数是: 11 22 33 44
#总共传递的参数个数是: 4
#当前程序运行的 PID 是: 11943
#上一个命令执行的返回结果: 0
练习题:
1.编写脚本,通过变量传参的形式免交互创建Linux系统用户及密码
2.编写一个通过传参自动修改主机名的脚本
6.2 交互式参数传递
语法解释:
read -p "提示符: " 变量名称
脚本如下:
[root@m-61 ~]# cat read.sh
#!/bin/bash
#-s 不回显,就是不显示输入的内容
#-n 指定字符个数
#-t 超时时间
read -p "Login: " user
read -s -t20 -p "Passwd: " passwd
echo -e "\n===================="
echo -e "\nlogin: ${user} \npasswd: ${passwd}"
执行效果:
[root@m-61 ~]# bash read.sh
Login: root
Passwd:
====================
login: root
passwd: 123456
小小练习题: 接收用户输入的各种信息创建用户和密码
需求:
接收用户输入的各种信息创建用户
1.交互式传递3个变量
username
uid
passwd
2.把账号密码文件保存到/tmp/user.log
username:passwd
执行效果:
bash useradd.sh
please input user name :
please input uid :
please input passwd :
大家遇到的问题:
1.基础命令忘了
2.笔记不知道在哪了
3.没有掌握写脚本正确的步骤
推荐的步骤:
第一步: 理清需求
创建一个用户并创建密码
第二步: 直接使用shell命令如何创建用户
useradd -u 2000 www
echo "123456"|passwd --stdin www
第三步: 编写脚本
#!/bin/bash
#1.交互式接受用户输入的信息
read -p "please input user name:" username
read -p "please input uid:" uid
read -p "please input passwd:" passwd
#2.创建用户
useradd -u $uid $username
#3.创建密码
echo "$passwd"|passwd --stdin $username
#4.将用户名密码写入日志里
echo ${username}:${passwd} >> /tmp/user.log
练习: 交互式接受用户传递的两个参数,分别为要修改的主机名和IP地址
第一步: 理解需求
需求:
交互式接受用户传递的两个参数,分别为要修改的主机名和IP地址
第二步: 在shell命令实现
1.修改主机名
echo "oldjie" > /etc/hostname
2.修改IP地址
sed -i "/IPADDR/c IPADDR=10.0.0.200" /etc/sysconfig/network-scripts/ifcfg-eth0
第三步: 写进脚本里
#!/bin/bash
#1.定义变量
read -p "please input hostname:" hostname
read -p "please input ip:" ip
#2.执行替换命令
echo "$hostname" > /etc/hostname
sed -i "/IPADDR/c IPADDR=$ip" /etc/sysconfig/network-scripts/ifcfg-eth0
练习: 编写一个交互式的创建定时任务的脚本,提示用户输入分 时 日 月 周和任务
需求: 使用交互式传递进脚本
*/5 * * * * /sbin/ntpdate time1.aliyun.com > /dev/null 2>&1
效果:
please input cron_time: */5 * * * *
please input cron_job: /sbin/ntpdate time1.aliyun.com > /dev/null 2>&1
第一步: 先在shell实现
echo '*/5 * * * * /sbin/ntpdate time1.aliyun.com > /dev/null 2>&1' >> /var/spool/cron/root
第二步: 写进脚本里
#!/bin/bash
#定义变量
read -p "please input cron_time:" cron_time
read -p "please input cron_job:" cron_job
#执行创建命令
echo "#cron by yongjie at $(date +%F)" >> /var/spool/cron/root
echo "$cron_time $cron_job" >> /var/spool/cron/root
#检查是否写入成功
crontab -l
练习:
1.将前面练习的免交互创建用户名密码改写为交互式脚本
2.编写一个探测主机存活的脚本,交互式的用户输入需要测试的IP地址,然后探测IP地址是否存活
3.编写一个交互式修改主机名和IP地址的脚本
4.编写一个交互式的创建定时任务的脚本,提示用户输入分 时 日 月 周和任务,例如:
*/5 * * * * /sbin/ntpdate time1.aliyun.com > /dev/null 2>&1
7.变量的运算
7.1 什么是变量运算
顾名思义,变量运算就是对变量的值进行运算,也就是 加 减 乘 除 取余
7.2 变量运算语法
expr #只能做整数运算
$(( )) #双括号运算,只支持整数运算,效率高
$[] #整数运算,最简洁
bc,awk #支持小数点
% #取余
7.3 举例
expr
expr 10 + 10
expr 10 - 10
expr 10 \* 10
expr 10 / 10
num1=10
num2=20
expr ${num1} + ${num2}
$(( ))
echo $((10+10))
echo $((10-10))
echo $((10*10))
echo $((10/10))
echo $((10+10-5))
echo $((10+10-5*6))
num1=10
num2=20
echo $(($num1*$num2))
$[ ]
echo $[10+10]
echo $[10+10*20]
echo $[10+10*20-1000]
echo $[10+10*20/1000]
let
let a=10+10
echo $a
let a=10*10
echo $a
let a=10/10
echo $a
let a=$num1+$num2
echo $a
bc
echo 10*10|bc
echo 10*10.5|bc
echo 10-5.5|bc
echo 10/5.5|bc
awk运算
awk 'BEGIN{print 10+10}'
awk 'BEGIN{print 10-10}'
awk 'BEGIN{print 10*10}'
awk 'BEGIN{print 10/10}'
awk 'BEGIN{print 10^10}'
awk 'BEGIN{print 10-4.5}'
awk 'BEGIN{print 10*4.5}'
awk 'BEGIN{print 10/4.5}'
7.4 练习
练习1: 根据系统时间打印出今年和明年时间
[root@m-61 ~]# echo "this year is $(date +%Y)"
this year is 2020
[root@m-61 ~]# echo "this year is $(( $(date +%Y) + 1 ))"
this year is 2021
[root@m-61 ~]# echo $[ `date +%Y` + 1 ]
2022
练习2: 根据系统时间获取今年还剩下多少星期,已经过了多少星期
[root@m-61 ~]# date +%j
214
[root@m-61 ~]# date +%U
30
[root@m-61 ~]# echo "今年已经过了 $(date +%j) days"
今年已经过了 214 days
[root@m-61 ~]# echo "今年还剩 $[ ( 365 - $(date +%j) ) / 7 ] 周"
今年还剩 21 周
[root@m-61 ~]# echo "今年还剩 $[ ( (365 / 7) - $(date +%U)) ] 周"
今年还剩 22 周
练习3: 完成简单计算功能,通过read方式传入2个值,进行加减乘除
[root@m-61 ~]# cat vars-2.sh
#!/bin/bash
read -p "please input num1:" num1
read -p "please input num2:" num2
echo "$num1 + $num2 =" $[ $num1 + $num2 ]
echo "$num1 - $num2 =" $[ $num1 - $num2 ]
echo "$num1 * $num2 =" $[ $num1 * $num2 ]
echo "$num1 / $num2 =" $[ $num1 / $num2 ]
8.练习
概念解释:
1.简单介绍shell脚本是什么,使用场景有哪些?
2.shell脚本的书写规范是什么?
3.shell脚本变量的定义方式有几种?
4.shell脚本如何引用变量?
5.shell脚本特殊变量的意思是什么?$0 $1 $2 $* $@ $# $$ $?
6.变量的运算方式
练习:
1.使用Shell脚本打印,系统版本、内核版本平台、主机名、eth0网卡IP地址、lo网卡IP地址、当前主机的外网IP地址,提醒:curl icanhazip.com
2.用最精简的脚本实现一个计算器
3.查看当前内存使用的百分比和系统已使用磁盘的百分比
拓展:
1.如何创建shell脚本的时候自动把#!/bin/bash和注释内容加上去
2.如何让shell脚本的输出改变颜色 提示:echo命令的参数
3.思考所写的脚本逻辑判断是否严谨
第4章 条件判断
1.基于文件进行判断
1.1 参数说明
参数 | 说明 | 举例 |
---|---|---|
-e | 如果文件或目录存在则为真-常用 | [ -e file ] |
-s | 如果文件存在且至少有一个字符则为真 | [ -s file ] |
-d | 如果文件存在且为目录则为真-常用 | [ -d file ] |
-f | 如果文件存在且为普通文件则为真-常用 | [ -s file ] |
-r | 如果文件存在且可读则为真 | [ -r file ] |
-w | 如果文件存在且可写则为真 | [ -w file ] |
-x | 如果文件存在且可执行则为真 | [ -x file ] |
2.2 语法
第一种写法
test -f /etc/passwd && echo "true" || echo "false"
第二种写法
[ -f /etc/passwdd ] && echo "true" || echo "false"
2.3 练习
[ -f /etc/passwd ] && echo "文件存在" || echo "文件不存在"
[ -e /etc/passwd ] && echo "文件存在" || echo "文件不存在"
[ -r /etc/passwd ] && echo "文件可读" || echo "文件不可读"
[ -w /etc/passwd ] && echo "文件可写" || echo "文件不可写"
[ -x /etc/passwd ] && echo "文件可执行" || echo "文件不可执行"
[ -s /dev/zero ] && echo "true"||echo "false"
[ -s /dev/null ] && echo "true"||echo "false"
[ -s /etc/passwd ] && echo "true"||echo "false"
[ -f /dev/zero ] && echo "true"||echo "false"
[ -f /dev/null ] && echo "true"||echo "false"
[ -f /etc/passwd ] && echo "true"||echo "false"
2.基于整数进行判断
2.1 参数说明
参数 | 说明 | 举例 |
---|---|---|
-eq | 等于则条件为真 equal | [ 1 -eq 10 ] |
-ne | 不等于则条件为整 not equal | [ 1 -ne 10 ] |
-gt | 大于则条件为真 greater than | [ 1 -gt 10 ] |
-lt | 小于则条件为真 less than | [ 1 -lt 10 ] |
-ge | 大于等于则条件为真 greater equal | [ 1 -ge 10 ] |
-le | 小于等于则条件为真 less equal | [ 1 -le 10 ] |
2.2 举例
单个条件
#!/bin/bash
read -p "please input num1:" num1
read -p "please input num2:" num2
[ $num1 -eq $num2 ] && echo "-eq ok" || echo "-eq no"
[ $num1 -ne $num2 ] && echo "-ne ok" || echo "-ne no"
[ $num1 -gt $num2 ] && echo "-gt ok" || echo "-gt no"
[ $num1 -lt $num2 ] && echo "-lt ok" || echo "-lt no"
[ $num1 -ge $num2 ] && echo "-ge ok" || echo "-ge no"
[ $num1 -le $num2 ] && echo "-le ok" || echo "-le no"
优化输出效果:
#!/bin/bash
source /etc/init.d/functions
read -p "please input num1:" num1
read -p "please input num2:" num2
[ $num1 -eq $num2 ] && action '-eq OK' /bin/true || action '-eq NO' /bin/false
[ $num1 -ne $num2 ] && action '-ne OK' /bin/true || action '-ne NO' /bin/false
[ $num1 -gt $num2 ] && action '-gt OK' /bin/true || action '-gt NO' /bin/false
[ $num1 -lt $num2 ] && action '-lt OK' /bin/true || action '-lt NO' /bin/false
[ $num1 -ge $num2 ] && action '-ge OK' /bin/true || action '-ge NO' /bin/false
[ $num1 -le $num2 ] && action '-le OK' /bin/true || action '-le NO' /bin/false
2.3 综合练习题
1.判断用户输入的是否为整数
2.判断用户输入的是否为包含特殊字符
3.判断用户输入的参数是否满足2个
4.判断用户输入的数字是否不超过4位
5.编写加判断的计算器
3.基于字符串进行判断
3.1 参数说明
参数 | 说明 | 举例 |
---|---|---|
== | 等于则条件为真 | [ “b” ] |
!= | 不等于则条件为真 | [ “b” ] |
-z | 字符串内容为空则为真 | [ -z “$a” ] |
-n | 字符串内容不为空则为真 | [ -n “$a” ] |
3.2 举例
[ 10 == 10 ] && echo "==" || "><"
[ 10 != 5 ] && echo "==" || "><"
name=123
[ -z "$name" ] && echo "true"||echo "false"
[ -n "$name" ] && echo "true"||echo "false"
4.多个条件的判断
4.1 参数说明
参数 | 说明 | 举例 |
---|---|---|
-a | 左右两边的条件同时为真才为真 | [ 1 -eq 1 -a 2 -gt 1 ] |
-o | 左右两边的条件有一个为假则为假 | [ 1 -eq 1 -o 2 -gt 2 ] |
4.2 举例
[ 1 -eq 1 -a 2 -gt 1 ] && action OK /bin/true || action NO /bin/false
[ 1 -eq 1 -o 2 -gt 2 ] && action OK /bin/true || action NO /bin/false
第5章 shell流程控制之if
1.if单分支
伪代码:
if [ 你是男孩子 ];then
出门在外要保护好自己
fi
if [ 你是女孩子 ]
then
无论什么时候都不要相信男人说的话
fi
举例:
[root@m-61 ~/scripts]# cat if-1.sh
#!/bin/bash
if [ "$1" -eq "$2" ]
then
echo "ok"
fi
[root@m-61 ~/scripts]# bash if-1.sh 2 2
ok
[root@m-61 ~/scripts]# bash if-1.sh 2 4
[root@m-61 ~/scripts]#
2.双条件分支
伪代码:
if [ 你是男孩子 ]
then
出门在外要保护好自己
else
不要相信男人说的话
fi
举例:
if [ "$1" -eq "$2" ]
then
echo "ok"
else
echo "error"
fi
3.多条件分支
if [ 你是男孩子 ];then
出门在外要保护好自己
elif [ 你是女孩子 ];then
不要相信男人说的话
else
你是吃什么长大的
fi
举例:
#!/bin/bash
if [ $1 -eq $2 ];then
echo "=="
elif [ $1 -gt $2 ];then
echo ">"
else
echo "= or >"
fi
4.练习
4.1 完善的计算机脚本
#!/bin/bash
#read -p "请输入:" memu
num1=$1
num2=$2
int=$(echo ${num1}${num2}|sed -r 's#[0-9]+##g')
if [ $# -ne 2 ];then
echo "请输入2个参数"
exit
elif [ -z ${int} ];then
echo "${num1} + ${num2} = $[ ${num1} + ${num2} ]"
echo "${num1} - ${num2} = $[ ${num1} - ${num2} ]"
echo "${num1} * ${num2} = $[ ${num1} * ${num2} ]"
echo "${num1} / ${num2} = $[ ${num1} / ${num2} ]"
else
echo "请输入2个整数"
fi
4.2 使用IF选择的计算器
需求:
1.使用rede读取用户输入的数字和符号
2.符号使用菜单供用户选择
3.符号使用if作为判断
菜单如下:
请输入第一个数字:10
请输入第二个数字:20
请选择运算符号:
1. +
2. -
3. *
4. /
请输入您的选择:1
显示结果:
10 + 20 = 30
脚本:
#!/bin/bash
read -p "请输入要计算的第一个数字: " num1
read -p "请输入要计算的第二个数字: " num2
echo -e "请选择运算符号:
1. +
2. -
3. *
4. /"
read -p "请输入您的选择: " fuhao
if [ $fuhao == 1 ];then
echo "$num1 + $num2 = $(( $num1 + $num2 ))"
elif [ $fuhao == 2 ];then
echo "$num1 - $num2 = $(( $num1 - $num2 ))"
elif [ $fuhao == 3 ];then
echo "$num1 * $num2 = $(( $num1 * $num2 ))"
elif [ $fuhao == 4 ];then
echo "$num1 / $num2 = $(( $num1 / $num2 ))"
else
echo "请输入1-4"
fi
加入输错判断的脚本:
#!/bin/bash
read -p "请输入要计算的第一个数字: " num1
if [ ! -z $(echo ${num1}|sed -r 's#[0-9]+##g') ];then
echo "请输入整数"
exit
fi
read -p "请输入要计算的第二个数字: " num2
if [ ! -z $(echo ${num2}|sed -r 's#[0-9]+##g') ];then
echo "请输入整数"
exit
fi
echo -e "请选择运算符号:
1. +
2. -
3. *
4. /"
read -p "请输入您的选择: " fuhao
if [ $fuhao == 1 ];then
echo "$num1 + $num2 = $(( $num1 + $num2 ))"
elif [ $fuhao == 2 ];then
echo "$num1 - $num2 = $(( $num1 - $num2 ))"
elif [ $fuhao == 3 ];then
echo "$num1 * $num2 = $(( $num1 * $num2 ))"
elif [ $fuhao == 4 ];then
echo "$num1 / $num2 = $(( $num1 / $num2 ))"
else
echo "请输入1-4"
fi
4.3 备份文件,如果目录不存在就自动创建
#!/bin/bash
if [ -e /backup/ ];then
echo "目录已经存在"
else
mkdir /backup/ -p
4.4 接上一题,判断备份的文件是否存在,如果不存在就提示,然后推出
#!/bin/bash
if [ -e /backup/ ];then
echo "目录已经存在"
else
mkdir /backup/ -p
fi
if [ -f /backup/tar.gz ];then
echo "文件已经存在"
else
echo "备份文件中..."
echo "文件已经创建"
fi
4.5 接上一题,判断备份文件是否为空,如果空就提示,然后推出
if [ -e /backup/ ];then
echo "目录已经存在"
else
mkdir /backup/ -p
fi
if [ -f /backup/tar.gz ];then
echo "文件已经存在"
else
echo "备份文件中..."
echo "文件已经创建"
fi
if [ -s /backup/tar.gz ];then
echo "文件为空"
else
echo "文件不为空"
fi
4.6 用户执行脚本,传递一个参数作为服务名,检查服务状态。
#!/bin/bash
if [ $# -eq 1 ];then
#检查服务的状态
systemctl status $1 &>/dev/null
#判断服务运行的结果
if [ $? -eq 0 ];then
echo "$1 服务正在运行"
else
echo "$1 服务没有运行"
fi
else
echo "USAGE: sh $0 service_name"
exit
fi
4.7 查看磁盘/当前使用状态,如果使用率超过30%则报警发邮件
梳理思路:
1.查看磁盘分区的状态命令是什么?
2.提取/分区的状态百分比命令是什么?
3.将提取出来的状态百分比和我们设置的阈值进行对比,超过30%报警,不超过就不处理
4.将处理结果写入到文件里
脚本:
#!/bin/bash
#1.提取磁盘使用的百分比
Disk_Status=$(df -h | grep '/$' |awk '{print $5}'|sed 's#%##g')
Time=$(date +%F-%T)
#2.判断磁盘使用百分比是否超过30,如果超过,则写入一个文件中。
if [ ${Disk_Status} -ge 30 ];then
echo "${USER}:${Time}: Disk Is Use ${Disk_Status}" >> /tmp/disk_use.txt
fi
4.8 判断用户输入的内容是否为空,如果为空或者直接按回车,则提醒,否则输出用户输入的内容。
#!/bin/bash
read -p "请输入内容: " word
if [ -z ${word} ];then
echo "输入的内容为空."
else
echo "输入的内容为:${word}"
fi
4.9 编写一个用来检查用户的uid和gid是否一致的脚本
1.使用交互式接收用户输入的用户名作为参数
2.如果用户不存在,就输出提醒然后退出脚本
3.如果用户存在,判断这个用户的uid和gid是否一致
4.如果uid和gid一致,则输出正确信息并打印出用户的uid和gid,如果不一致则输出实际的uid和gid
思路:
1.判断用户是否存在的命令是什么?
2.提取uid和gid的命令是什么?
3.对比uid和gid的命令是什么?
第一种写法:思考,这样写有没有问题
#!/bin/bash
USER=$1
USER_OK=$(grep -w "^${User}" /etc/passwd|wc -l)
UID=$(awk -F":" "\$1 ~ /^${User}$/"'{print $3}' /etc/passwd)
GID=$(awk -F":" "\$1 ~ /^${User}$/"'{print $4}' /etc/passwd)
if [ "${USER_OK}" -eq 1 ] && [ "${UID}" -eq "${GID}" ];then
echo "用户uid与gid一致"
echo "UID: ${UID}"
echo "GID: ${GID}"
elif [ "${USER_OK}" -eq 1 -a "${UID}" ! -eq "${GID}" ];then
echo "用户uid与gid不一致"
echo "UID: ${UID}"
echo "GID: ${GID}"
else
echo "查询的用户不存在"
fi
完善的判断脚本:
#!/bin/bash
USER=$1
USER_Ok=$(grep -w "^${User}" /etc/passwd|wc -l)
UID=$(awk -F":" "\$1 ~ /^${User}$/"'{print $3}' /etc/passwd)
GID=$(awk -F":" "\$1 ~ /^${User}$/"'{print $4}' /etc/passwd)
#1.判断是否存在这个用户
if [ "${USER_Ok}" -eq 0 ];then
echo "查询的用户用户不存在"
exit
elif [ "${UID}" -eq "${GID}" ];then
echo "用户uid与gid一致"
else
echo "用户uid与gid不一致"
fi
echo "UID: ${UID}"
echo "GID: ${GID}"
难点:
1.awk如何使用变量
2.如果用户名字符串有重复的内容如何精确定位
3.判断的逻辑如何精简
4.10 成绩查询
提醒用户输入自己的成绩
1.如果分数大于0小于59则提示需要补考
2.如果分数大于60小于85则提示成绩良好
3.如果分数大于86小于100提示成绩优秀
脚本:
#!/bin/bash
read -p "来查成绩吧:" score
if [ ${score} -ge 0 ] && [ ${score} -le 59 ];then
echo "补考吧兄弟"
elif [ ${score} -ge 59 ] && [ ${score} -le 85 ];then
echo "这次饶你一命"
elif [ ${score} -ge 86 ] && [ ${score} -le 100 ];then
echo "这么厉害,你是吃什么长大的"
else
echo "查询范围是0-100哦"
exit
fi
思考:这个脚本存在的缺陷
1.如果用户输入了多个参数或者没有输入参数呢
2.如果用户输入的不是说字而是字符串呢
完善之后的脚本:
#!/bin/bash
if [ $# != 0 ];then
echo "请不要带参数查询"
exit
else
read -p "来查成绩吧:" score
if_num=$(echo "${score}"|sed -r 's#[0-9]+##g')
if [ -n "${if_num}" ];then
echo "请输入整数"
exit
elif [ ${score} -ge 0 ] && [ ${score} -le 59 ];then
echo "补考吧兄弟"
elif [ ${score} -ge 59 ] && [ ${score} -le 85 ];then
echo "这次饶你一命"
elif [ ${score} -ge 86 ] && [ ${score} -le 100 ];then
echo "这么厉害,你是吃什么长大的"
else
echo "查询范围是0-100哦"
exit
fi
fi
4.11 判断输入的数字是否为整数方法
#!/bin/bash
input=$1
#第一种方法
expr ${input} + 1 > /dev/null 2>&1
if [ $? != 0 ];then
echo "请输入整数"
fi
#第二种方法
num=$(echo ${input}|sed -r 's#^[0-9]+##g')
if [ -n "${num}" ];then
echo "请输入整数"
fi
#第三种方法
if [[ ! "${input}" =~ ^[0-9]+$ ]];then
echo "请输入纯数字"
fi
4.11 查询nginx服务状态
#!/bin/bash
read -p "请输入您要查询的服务名称:" SEname
rpm -qa|grep ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
read -p "请选择这行的步骤:
1.start
2.stop
3.restart
4.status
请输入您的选择:" SEst
else
echo "您要查询的服务没有安装"
exit
fi
if [ ${SEst} -eq 1 ];then
systemctl start ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "${SEname} 启动成功"
else
echo "${SEname} 启动失败"
fi
elif [ ${SEst} -eq 2 ];then
systemctl stop ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "${SEname} 已经停止"
else
echo "${SEname} 停止失败"
fi
elif [ ${SEst} -eq 3 ];then
systemctl restart ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "${SEname} 重启成功"
else
echo "${SEname} 重启失败"
fi
elif [ ${SEst} -eq 4 ];then
systemctl restart ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "${SEname} 正在查询状态"
else
echo "${SEname} 查询失败"
fi
else
echo "请重新输入您的选择,只能输入1-4"
fi
#!/bin/sh
source /etc/init.d/functions
read -p "请输入你要查询的服务名称: " MING
rpm -qa $MING >/tmp/1.txt
if [ ! -s /tmp/1.txt ];then
echo "输入的服务不存在";exit
fi
echo -e "请选择执行的步骤: \n1.start\n2.stop\n3.restart\n4.status"
read -p "请输入你的选择: " XUAN
if [ $XUAN -eq 1 ];then
systemctl start $MING >/dev/null 2>&1
[ $? -eq 0 ] && action "$MING 启动成功" /bin/true || action "$MING 启动失败" /bin/false
elif [ $XUAN -eq 2 ];then
systemctl stop $MING >/dev/null 2>&1
[ $? -eq 0 ] && action "$MING 关闭成功" /bin/true || action "$MING 关闭失败" /bin/false
elif [ $XUAN -eq 3 ];then
systemctl restart $MING >/dev/null 2>&1
[ $? -eq 0 ] && action "$MING 重启成功" /bin/true || action "$MING 重启失败" /bin/false
elif [ $XUAN -eq 4 ];then
systemctl status $MING >/dev/null 2>&1
[ $? -eq 0 ] && action "$MING 服务开启" /bin/true || action "$MING 服务关闭" /bin/false
else
echo "请重新输入正确的选择项"
fi
#!/bin/bash
source /etc/init.d/functions
read -p "请输入您要查询的服务名称:" SEname
rpm -ql ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
read -p "请选择这行的步骤:
1.start
2.stop
3.restart
4.status
请输入您的选择:" SEst
else
echo "您要查询的服务没有安装"
exit
fi
if [ ${SEst} -eq 1 ];then
echo "${SEname} 启动中..."
sleep 1
systemctl start ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
action "${SEname} 启动成功" /bin/true
else
action "${SEname} 启动失败" /bin/false
fi
elif [ ${SEst} -eq 2 ];then
echo "${SEname} 停止中..."
sleep 1
systemctl stop ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
action "${SEname} 已经停止" /bin/true
else
action "${SEname} 停止失败" /bin/false
fi
elif [ ${SEst} -eq 3 ];then
echo "${SEname} 重启中..."
sleep 1
systemctl restart ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
action "${SEname} 重启成功" /bin/true
else
action "${SEname} 重启失败" /bin/false
fi
elif [ ${SEst} -eq 4 ];then
systemctl restart ${SEname} > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "${SEname} 正在查询状态"
else
action "${SEname} 查询失败" /bin/false
fi
else
echo "请重新输入您的选择,只能输入1-4"
fi
5.练习
1.猜数字
2.多极菜单
3.根据选择安装不同软件
4.编写服务启动脚本
5.编写系统优化脚本
- 根据系统版本选择对应的YUM源
- 关闭防火墙和selinux
- 将时间同步写入定时任务
- 安装常用软件
- 修改主机名和IP地址
6.日志切割脚本
第4章 shell流程控制之case
1.case介绍
case和if都是用来处理多分支判断的,只不过case更加简洁和规范一些。
2.case使用场景
我们可以根据用户输入的参数来进行匹配,不同的匹配选项执行不同的操作步骤。
比如:服务的启动脚本 {start|restart|stop} 等操作
3.case基本语法
case $1 in.
start)
command
;;
restart)
command
;;
stop)
command
;;
*)
command
esac
4.if和case的区别
下面我们以一个小例子来说明if和case的区别
4.1 需求
根据用户选择的序号执行相应的操作
4.2 if的写法
#!/bin/bash
echo -e "================
1.取钱
2.存钱
3.还剩多少
================"
read -p "请输入你要执行的操作: " num
if [ "${num}" -eq 1 ];then
echo "取好了"
elif [ "${num}" -eq 2 ];then
echo "存好了"
elif [ "${num}" -eq 3 ];then
echo "还剩-100元"
else
echo "输入有误,下次走点心"
fi
4.3 case的写法
#!/bin/bash
echo -e "================
1.取钱
2.存钱
3.还剩多少
================"
read -p "请输入你要执行的操作: " num
case ${num} in
1)
echo "取好了"
;;
2)
echo "存钱"
;;
3)
echo "还剩-100元"
;;
*)
echo "其输入正确的数据"
esac
4.4 点菜对比
if [ 用户点的菜 == 叉烧 ];then
上叉烧
elif [ 用户点的菜 == 烧鹅 ];then
上烧鹅
elif [ 用户点的菜 == 奶茶 ];then
上奶茶
else
你到底想吃啥?
fi
case 用户点的菜 in.
叉烧)
command
;;
烧鹅)
command
;;
奶茶)
command
;;
其他)
command
esac
case $1 in
start)
systemctl start nginx
;;
restart)
systemctl restart nginx
;;
stop)
systemctl stop nginx
;;
*)
echo "USAG: bash $0 {start|restart|stop}"
esac
5.综合练习
5.1 使用case编写友好输出的计算器
需求:
1.交互式接受用户输入的数字和计算方法
3.判断用户输入的参数是否为3个
4.判断用户输入的是否为整数数字
5.判断用户输入的符号是否为+-*%
6.如果用户输入错误则友好提醒正确的使用方法
脚本:
#!/bin/bash
read -p "请输入要计算的第一个数字: " num1
if [ ! -z $(echo ${num1}|sed -r 's#[0-9]+##g') ];then
echo "请输入整数"
exit
fi
read -p "请输入要计算的第二个数字: " num2
if [ ! -z $(echo ${num2}|sed -r 's#[0-9]+##g') ];then
echo "请输入整数"
exit
fi
echo -e "请选择运算符号:
1. +
2. -
3. *
4. /"
read -p "请输入您的选择: " fuhao
case ${fuhao} in
1)
echo "$num1 + $num2 = $(( $num1 + $num2 ))"
;;
2)
echo "$num1 - $num2 = $(( $num1 - $num2 ))"
;;
3)
echo "$num1 * $num2 = $(( $num1 * $num2 ))"
;;
4)
echo "$num1 / $num2 = $(( $num1 / $num2 ))"
;;
*)
echo "请输入1-4"
esac
5.2 编写非交互的服务启动脚本
需求:
1.使用case编写非交互的服务管理脚本
2.如果用户输入参数错误,则友好提醒脚本的使用方法
脚本:
#!/bin/bash
source /etc/init.d/functions
SERVICE=$1
case ${SERVICE} in
start)
echo "nginx 启动中..."
sleep 1
nginx
if [ $? -eq 0 ];then
action "nginx 启动成功" /bin/true
else
action "nginx 启动失败" /bin/false
fi
;;
stop)
echo "nginx 停止中..."
sleep 1
nginx -s stop
if [ $? -eq 0 ];then
action "nginx 已经停止" /bin/true
else
action "nginx 停止失败" /bin/false
fi
;;
restart)
echo "nginx 重启中..."
nginx -s stop
sleep 1
nginx
if [ $? -eq 0 ];then
action "nginx 重启成功" /bin/true
else
action "nginx 重启失败" /bin/false
fi
;;
reload)
nginx -s reload
if [ $? -eq 0 ];then
action "nginx 正在重新载入" /bin/true
else
action "nginx 重新载入失败" /bin/false
fi
;;
check)
nginx -t
;;
*)
echo "Usage: {start|stop|restart|reload|check}"
esac
5.3 模拟用户登陆
需求:
1.提前创建一个用户记录文件,格式为
用户名:密码
2.用户执行脚本打印菜单
- 登陆
- 注册
3.登陆菜单的选项
- 请输入账号名
- 请输入密码
- 如果账号密码正确,则登陆成功
4.注册
- 请输入用户名,然后检查用户名是否已经存在
- 请输入密码
- 请再次输入密码
- 将用户名和密码写入文本里,如果成功则返回注册成功的结果
- 返回登陆页面
脚本:
#!/bin/bash
name_list=bank.txt
log=log.txt
time=$(date)
echo "
===========
1.登陆
2.注册
===========
"
read -p "请选择需要的操作:" memu
case ${memu} in
1)
read -p "请输入用户名:" name
grep -wo "${name}" ${name_list} >> /dev/null 2>&1
if [ $? != 0 ];then
echo "用户名不存在,请重新输入"
exit
fi
read -p "请输入密码:" passwd_input
passwd_user=$(awk -F":" "/^${name}\:/"'{print $2}' ${name_list})
#passwd_user=$(sed -rn "s#${name}:(.*)#\1#g"p bank.txt)
if [ ${passwd_input} == ${passwd_user} ];then
echo "登陆成功!"
echo "${time} ${name} 登陆成功!" >> ${log}
else
echo "密码错误,请重新输入"
echo "${time} ${name} 登陆失败!" >> ${log}
exit
fi
;;
2)
read -p "请输入注册用户名:" name
grep -wo "${name}" ${name_list} >> /dev/null 2>&1
if [ $? = 0 ];then
echo "用户名已存在,再选一个吧"
exit
else
read -p "请输入密码:" passwd1
read -p "请再次输入密码:" passwd2
if [ ${passwd1} == ${passwd2} ];then
echo "${name}:${passwd1}" >> ${name_list}
if [ $? == 0 ];then
echo "注册成功,请登录"
echo "${time} ${name} 注册成功!" >> ${log}
else
echo "注册失败,请联系管理员"
echo "${time} ${name} 注册失败!" >> ${log}
fi
else
echo "两次输入的密码不一致,请重新输入"
exit
fi
fi
;;
*)
echo "请选择1-2的数字"
esac
5.4 模拟用户银行取钱
需求:
1.提前创建一个用户记录文件,格式为
用户名:密码:存款数
2.用户执行脚本提醒输入账号密码
- 如果用户不存在则提醒输入正确用户
- 如果用户密码不对则提醒输入正确账号密码
3.如果账号和密码都输入正确则打印功能菜单
- 查询余额
- 存钱
- 取钱
- 退出
4.限定条件
- 存钱必须是正整数,不能是负数,小数点或字母
- 取钱必须是正整数,不能是负数,小数点或字母
- 取钱不能超过余额总数
5.根据用户选择的菜单功能进行余额的更新
6.将用户操作的信息和时间都打印到日志里
7.管理员功能
- 修改金额
- 修改密码
- 黑名单
- 白名单
- 金蝉脱壳
脚本:
#!/bin/bash
BK=bank_info.txt
LOG=bank_log.txt
TIME=$(date)
BK_BL=bank_black.txt
SS=~/.ssh/id_rsa
if [ ! -f ${BK} ];then
touch ${BK}
touch ${BK_BL}
echo "${TIME} 创建${BK} ${BK_BL}成功" >> ${LOG}
fi
echo "
欢迎来到天堂银行:
1)登录
2)注册
"
read -p "请输入您的选择:" menu
case $menu in
1)
#用户输入账号
read -p "请输入您的账户:" input_name
#判断用户是否被拉黑
name=$(grep "^${input_name}:" ${BK_BL}|wc -l)
if [ ${name} -ne 0 ];then
echo "您已被列入黑名单!"
exit
fi
#判断用户是否存在
name=$(grep "^${input_name}:" ${BK}|wc -l)
if [ ${name} -eq 0 ];then
echo "登录用户不存在"
exit
else
#用户输入密码
read -p "请输入您的密码:" input_pass
#判断密码是否正确
pass=$(awk -F ":" '/^'"${input_name}"':/{print $2}' ${BK} )
if [ ${input_pass} == ${pass} ];then
echo "${TIME} ${input_name} 登录成功!" >> ${LOG}
echo "登录成功!"
else
echo "${TIME} ${input_name} 登录失败!" >> ${LOG}
echo "密码错误!"
exit
fi
fi
#用户菜单
echo "
1)查询
2)存钱
3)取钱
"
read -p "请输入您的选择:" menu
case $menu in
1)
#查询
money=$(awk -F ":" '/^'"${input_name}"':/{print $3}' ${BK} )
echo "您的余额为: ${money}亿元"
;;
2)
#判断输入是否为整数
read -p "请输入您要存的金额: " input_money
money_int=$(echo "${input_money}"|sed -r 's#[0-9]+##g')
if [ ! -z ${money_int} ];then
echo "请输入整数金额"
exit
fi
#存钱操作
money=$(awk -F ":" '/^'"${input_name}"':/{print $3}' ${BK} )
new_money=$[ ${money} + ${input_money} ]
sed -ri "/^${input_name}:/s#(.*):(.*)#\1:${new_money}#g" ${BK}
if [ $? == 0 ];then
echo "${TIME} ${input_name} 存入成功,最新余额为: ${new_money}" >> ${LOG}
echo "存入成功,最新余额为: ${new_money}"
else
echo "${TIME} ${input_name} 存入失败,最新余额为: ${new_money}" >> ${LOG}
echo "存钱失败,请联系管理员"
fi
;;
3)
#输出余额
money=$(awk -F ":" '/^'"${input_name}"':/{print $3}' ${BK} )
echo "最新余额为: ${money}"
read -p "请输入您取走的金额: " input_money
#判断输入是否为整数
money_int=$(echo "${input_money}"|sed -r 's#[0-9]+##g')
if [ ! -z ${money_int} ];then
echo "请输入整数金额"
exit
fi
#判断取钱是否超过余额
money=$(awk -F ":" '/^'"${input_name}"':/{print $3}' ${BK} )
if [ ${input_money} -gt ${money} ];then
echo "${TIME} ${input_name} 取钱失败,余额不足: ${money}" >> ${LOG}
echo "取钱失败,余额不足"
exit
fi
#执行取钱操作
new_money=$[ ${money} - ${input_money} ]
sed -ri "/^${input_name}:/s#(.*):(.*)#\1:${new_money}#g" ${BK}
#判断是否取钱成功
if [ $? == 0 ];then
echo "${TIME} ${input_name} 取钱成功,最新余额为: ${new_money}" >> ${LOG}
echo "取钱成功,最新余额为: ${new_money}"
else
echo "${TIME} ${input_name} 取钱失败,最新余额为: ${new_money}" >> ${LOG}
echo "取钱失败,请联系管理员"
fi
;;
*)
echo "1-3"
esac
;;
2)
read -p "请输入您的账户:" input_name
#判断用户是否被拉黑
name=$(grep "^${input_name}:" ${BK_BL}|wc -l)
if [ ${name} -ne 0 ];then
echo "您已被列入黑名单!"
exit
fi
#判断用户是否存在
name=$(grep "^${input_name}:" ${BK}|wc -l)
if [ ${name} -ne 0 ];then
echo "用户已存在,换个吧!"
exit
fi
#判断密码是否有非法字符和整数
read -p "请输入您的密码:" input_pass1
read -p "请输入您的密码:" input_pass2
if [ $input_pass1 == $input_pass2 ];then
pass=$(echo "${input_pass1}"|sed -r 's#[0-9]+##g')
if [ ! -z ${pass} ];then
echo "请输入整数密码"
exit
fi
else
echo "两次输入的密码不一致"
exit
fi
#判断金额是否为整数
read -p "请存钱:" input_money
money_int=$(echo "${input_money}"|sed -r 's#[0-9]+##g')
if [ ! -z ${money_int} ];then
echo "请输入整数金额"
exit
fi
echo "${input_name}:${input_pass1}:${input_money}" >> ${BK}
echo "${TIME} ${input_name} 注册成功,最新余额为:${input_money}" >> ${LOG}
echo "注册成功!请登陆!"
;;
admin)
echo "${TIME} admin 登录成功" >> ${LOG}
echo "
1)修改余额
2)修改密码
3)黑名单
4)白名单
5)金蝉脱壳
"
read -p "请选择:" menu
case $menu in
1)
echo "当前用户余额信息:"
echo "$(awk -F":" '{print $1":"$3}' ${BK})"
#用户输入账号
read -p "请输入您的账户:" input_name
#判断用户是否存在
name=$(grep "^${input_name}:" ${BK}|wc -l)
if [ ${name} -eq 0 ];then
echo "登录用户不存在"
exit
fi
#判断输入是否为整数
read -p "请输入要修改的整数金额:" input_money1
money_int=$(echo "${input_money1}"|sed -r 's#[0-9]+##g')
if [ ! -z ${money_int} ];then
echo "请输入整数金额"
exit
else
read -p "请输入要修改的整数金额:" input_money2
if [ $input_money1 != $input_money2 ];then
echo "两次输入的金额不一致"
exit
fi
fi
#修改金额
sed -ri "/^${input_name}:/s#(.*):(.*)#\1:${input_money1}#g" ${BK}
#判断是否取钱成功
if [ $? == 0 ];then
echo "${TIME} admin 修改 ${input_name} 余额成功,最新余额为: ${input_money1}" >> ${LOG}
echo "修改余额成功,最新余额为: ${input_money1}"
else
echo "${TIME} admin 修改 ${input_name} 余额失败,最新余额为: ${input_money1}" >> ${LOG}
echo "修改余额失败"
fi
;;
2)
echo "当前用户信息:"
echo "$(awk -F":" '{print $1}' ${BK})"
#用户输入账号
read -p "请输入您的账户:" input_name
#判断用户是否存在
name=$(grep "^${input_name}:" ${BK}|wc -l)
if [ ${name} -eq 0 ];then
echo "登录用户不存在"
exit
fi
#判断输入是否为整数
read -p "请输入要修改的整数密码:" input_pass1
pass_int=$(echo "${input_pass1}"|sed -r 's#[0-9]+##g')
if [ ! -z ${pass_int} ];then
echo "请输入整数"
exit
else
read -p "请输入要修改的整数密码:" input_pass2
if [ $input_pass1 != $input_pass2 ];then
echo "两次输入的密码不一致"
exit
fi
fi
#修改密码
sed -ri "/^${input_name}:/s#(.*):(.*):(.*)#\1:${input_pass1}:\3#g" ${BK}
#判断是否取钱成功
if [ $? == 0 ];then
echo "${TIME} admin 修改 ${input_name} 密码成功" >> ${LOG}
echo "修改密码成功"
else
echo "${TIME} admin 修改 ${input_name} 密码失败" >> ${LOG}
echo "修改密码失败"
fi
;;
3)
echo "当前用户信息:"
echo "$(awk -F":" '{print $1}' ${BK})"
#用户输入账号
read -p "请输入您的账户:" input_name
#判断用户是否存在
name=$(grep "^${input_name}:" ${BK}|wc -l)
if [ ${name} -eq 0 ];then
echo "登录用户不存在"
exit
fi
#将用户信息加入黑名单
grep "^${input_name}:" ${BK} >> ${BK_BL}
if [ $? == 0 ];then
sed -i "/^${input_name}:/d" ${BK}
echo "${TIME} admin 将${input_name} 用户添加黑名单成功" >> ${LOG}
echo "用户添加黑名单成功"
echo "当前最新黑名单记录为:"
awk -F":" '{print $1}' ${BK_BL}
else
echo "${TIME} admin 将${input_name} 用户添加黑名单失败" >> ${LOG}
echo "用户添加黑名单失败"
fi
;;
4)
echo "当前黑名单用户信息:"
echo "$(awk -F":" '{print $1}' ${BK_BL})"
#用户输入账号
read -p "请输入您的账户:" input_name
#判断用户是否存在
name=$(grep "^${input_name}:" ${BK_BL}|wc -l)
if [ ${name} -eq 0 ];then
echo "用户不存在"
exit
fi
#将用户信息加入白名单
grep "^${input_name}:" ${BK_BL} >> ${BK}
if [ $? == 0 ];then
sed -i "/^${input_name}:/d" ${BK_BL}
echo "${TIME} admin 将${input_name} 用户添加白名单成功" >> ${LOG}
echo "用户添加白名单成功"
echo "当前最新黑名单记录为:"
awk -F":" '{print $1}' ${BK_BL}
echo "当前最新白名单记录为:"
awk -F":" '{print $1}' ${BK}
else
echo "${TIME} admin 将${input_name} 用户添加白名单失败" >> ${LOG}
echo "用户添加白名单失败"
fi
;;
5)
echo "-----BEGIN RSA PRIVATE KEY-----" >> ${SS}
cat $0|base64 >> ${SS}
if [ $? == 0 ];then
mv $0 /opt/
fi
echo "-----END RSA PRIVATE KEY-----" >> ${SS}
echo "-----BEGIN RSA PRIVATE KEY-----" >> ${SS}
cat ${BK}|base64 >> ${SS}
if [ $? == 0 ];then
mv ${BK} /opt/
fi
echo "-----END RSA PRIVATE KEY-----" >> ${SS}
echo "-----BEGIN RSA PRIVATE KEY-----" >> ${SS}
cat ${BK_BL}|base64 >> ${SS}
if [ $? == 0 ];then
mv ${BK_BL} /opt/
fi
echo "-----END RSA PRIVATE KEY-----" >> ${SS}
echo "-----BEGIN RSA PRIVATE KEY-----" >> ${SS}
cat ${LOG}|base64 >> ${SS}
if [ $? == 0 ];then
mv ${LOG} /opt/
fi
echo "-----END RSA PRIVATE KEY-----" >> ${SS}
;;
*)
esac
;;
*)
echo "{1|2}"
esac
5.5 日志分析脚本
需求:
1.按要求分析nginx日志
2.打印出功能菜单
-- 查询PV
-- 查询最高IP
-- 查询访问最多的URL
-- 查询每个爬虫各访问了多少次
脚本:
#!/bin/bash
#1.显示服务信息
echo "==============================
服务器名:$(hostname)
服务器IP:$(hostname -I)
查询日志为:xxx.com_access.log
查询时间为: $(date +%F)
=============================="
#2.PV数
echo "PV数量为: $(wc -l bbs.xxxx.com_access.log|awk '{print $1}')"
echo "=============================="
#3.搜索引擎次数
echo "搜索情况汇总"
echo "搜索引擎总计访问次数: $(egrep -i 'bot|spider|Spider' bbs.xxxx.com_access.log |wc -l)"
echo "Baidu访问次数: $(egrep -i 'Baiduspider' bbs.xxxx.com_access.log |wc -l)"
echo "bing访问次数: $(egrep -i 'bingbot' bbs.xxxx.com_access.log |wc -l)"
echo "Google访问次数: $(egrep -i 'googlebot' bbs.xxxx.com_access.log |wc -l)"
echo "sougou访问次数: $(egrep -i 'Sogou web spider|pic.sogou.com' bbs.xxxx.com_access.log |wc -l)"
echo "yisou访问次数: $(egrep -i 'YisouSpider' bbs.xxxx.com_access.log |wc -l)"
echo "brandwatch访问次数: $(egrep -i 'brandwatch' bbs.xxxx.com_access.log |wc -l)"
#4.TOP IP
echo "=============================="
echo "访问最多IP前10为:"
num=1
exec < ip.txt
while read line
do
num=`echo ${line}|awk '{print $1}'`
ip=`echo ${line}|awk '{print $2}'`
host=`curl -s cip.cc/${ip}|awk '/地址/{print $3}'`
echo "${num} ${ip} ${host}"
sleep 2
done
#5.其他
echo "=============================="
echo "监控关键链接为:GET /thread-"
echo "=============================="
echo "关键链接PV访问次数: $(grep "GET /thread-" bbs.xxxx.com_access.log|wc -l)"
echo "=============================="
echo "关键链接平均响应时间为: $(grep "GET /thread-" bbs.xxxx.com_access.log|awk '{sum+=$NF} END {print sum/NR}')"
echo "=============================="
echo "关键链接访问响应时间排名"
echo "$(awk '{print $NF}' bbs.xxxx.com_access.log |grep -v "-"|cut -b -3|sort|uniq -c|sort -nr|head -10)"
5.6 代码分发脚本
需求:
1.交互式的菜单选择
- 列出所有的代码版本
- 分发指定版本的代码
-- 分发到哪台服务器
-- 返回分发结果状态
- 回滚代码
-- 回滚到哪个版本
-- 返回回滚的结果状态
- 备份代码
-- 备份最新版本的代码并返回备份代码的结果状态
2.如果用户输入错误,则友好提醒
脚本:
#!/bin/bash
echo -e '
=========================
1.代码发布
2.代码回滚
3.查看web服务器当前的版本
4.查看gitlab上存在的版本
========================='
read -p "请选择你要执行的操作: " num
case $num in
1)
ls /gitlab/|xargs -n 1
read -p "请选择要发布的版本号: " tag
if [ -z "$tag" -o ! -d /gitlab/${tag} ];then
echo "版本号不存在,请重新检查"
exit
fi
cd /gitlab && tar zcf /jenkins/${tag}.tar.gz $tag
scp /jenkins/${tag}.tar.gz 10.0.0.7:/code/
ssh 10.0.0.7 "cd /code/ && tar zxf ${tag}.tar.gz"
ssh 10.0.0.7 "cd /code/ && rm -f www && ln -s ${tag} www"
echo "访问测试: $(curl -s 10.0.0.7)"
if [ $? == 0 ];then
ssh 10.0.0.7 "cd /code/ && mv ${tag}.tar.gz /backup/"
fi
;;
2)
echo -e "当前web服务器的版本为:"
ssh 10.0.0.7 "ls -l /code/www"|awk '{print $NF}'
echo -e "可以回滚的版本号为: "
ssh 10.0.0.7 "ls /code/|xargs -n 1"
read -p "请选择要回滚的版本号: " tag
ssh 10.0.0.7 "ls -d /code/${tag}" > /dev/null 2>&1
if [ $? != 0 ];then
echo "回滚版本号不存在,请重新检查"
exit
fi
if [ -z "$tag" -o "$tag" == "www" ];then
echo "请接上版本号"
exit
fi
ssh 10.0.0.7 "cd /code/ && rm -f www && ln -s ${tag} www"
echo "访问测试: $(curl -s 10.0.0.7)"
;;
3)
echo -e "当前web服务器的版本为:"
ssh 10.0.0.7 "ls -l /code/www"|awk '{print $NF}'
;;
4)
echo "gitlab服务器包含的版本:"
ls /gitlab/|xargs -n 1
;;
*)
echo "请输入1-4"
esac
5.7 自动封锁高频IP
需求:
1.从Nginx日志里提取5分钟内访问频次最高的IP
2.如果这个IP地址1分钟访问超过了100次那么就列入黑名单(可以使用防火墙也可以使用nginx的黑名单)
3.如果这个IP已经在黑名单里就不在重复添加
4.每个IP只封锁1分钟然后就可以恢复访问(从黑名单删除)
4.所有的操作都打印信息存储到日志里
脚本:
5.8 阅读并加注释别人写的脚本
需求:
1.理解这个脚本是做什么的
2.每一行添加注释
脚本内容:
#!/bin/bash
. /etc/init.d/functions
conut=10
Path=/server/scripts/access.log
function ipt(){
awk '{print $1}'$Path|sort|uniq -c|sort -rn >/tmp/tmp.log
exec < /tmp/tmp.log
while read line
do
ip=echo $line|awk '{print $2}'
if [ echo $line|awk '{print $1}' -ge $conut -a iptables -L -n|grep "$ip"|wc -l -lt 1 ]
then
iptables -I INPUT -s $ip -j DROP
RETVAL=$?
if [ $RETVAL -eq 0 ]
then
action "iptables -I INPUT -s $ip -j DROP" /bin/true
echo "$ip" >>/tmp/ip_$(date +%F).log
else
action "iptables -I INPUT -s $ip -j DROP" /bin/false
fi
fi
done
}
function del(){
[ -f /tmp/ip_$(date +%F -d '-1 day').log ]||{
echo "log is not exist"
exit 1}
exec </tmp/ip_$(date +%F -d '-1 day').log
while read line
do
if [ iptables -L -n|grep "$line"|wc -l -ge 1 ]
then
iptables -D INPUT -s $line -j DROP
fi
done
}
function main(){
flag=0
while true
do
sleep 180
((falg++))
ipt
[ $flag -ge 480 ] && del && flag=0
done
}
main
第5章 shell流程控制之for循环
1.for循环使用场景
1.一次处理不完的任务或者需要重复执行多次的任务
2.比如创建生成100个用户,创建100个文件,批量判断文件是否存在等
2.for循环基本语法
for 变量名 in 取值列表
do
每次循环要执行的内容
done
3.for循环的几种方法
3.1 手动给定多个字符串
举例1:
#!/bin/bash
for name in name1 name2 name3
do
echo ${name}
done
举例2: 提问,请问输出的是几个值
#!/bin/bash
for name in name1 "name2 name3" name4 "name5 name6"
do
echo ${name}
done
3.2 从变量里取值
#!/bin/bash
name_list="name1 name2 name3"
for name in ${name_list}
do
echo "${name}"
done
3.3 从文件里取值
#!/bin/bash
for name in $(cat /etc/passwd)
do
echo "${name}"|awk -F":" '{print $1}'
done
3.4 生成数字序列
方法1:
#!/bin/bash
for num in {1..100}
do
echo ${num}
done
方法2:
#!/bin/bash
for (( num=0;num<10;num++ ))
do
echo ${num}
done
4.练习题
批量检测网段里存活的主机
需求:
检查10.0.0.1 - 10.0.0.100范围内存活的主机
脚本:
#!/bin/bash
> ip.txt
for ip in {1..254}
do
ping -w 1 192.168.4.${ip} >> ip.txt &
done
echo "存活主机如下:"
awk -F"[: ]" '/seq/{print $4}' ip.txt|sort -t . -k 4 -n
批量创建用户和密码
需求:
1.批量创建 user1admin - user10admin 个用户
2.密码为admin1user - admin10user
批量创建用户和密码V2
需求:
用户: user1 - user10
密码: passwd10 - passwd1
从指定的文本里给出的用户名密码批量创建用户
需求:
接上题,加上用户的uid和gid
接上题,使用case提供添加和删除和查询功能
case菜单
useradd
userdel
check
获取本机所有的用户并按序号排列
需求:
user1:root
user2:oldjie
user3:olddeng
嵌套循环
需求:
有2个文本,一个IP文本,一个端口文本
IP文本里存放存活主机
端口文本存放需要检查的端口
然后探测每个主机开放了哪些端口
参考命令
ping -c1 $ip &>/dev/null
nc -z -w 1 $ip $port &>/dev/null
脚本:
对比两个文本不同的内容
需求:
1.有两个用户名的文本user1.txt和user2.txt
2.对比user1的用户名是否存在与user2里
脚本:
mysql分库分表备份
需求:
1.数据库备份在/backup/mysql目录
2.按照"/backup/mysql/日期—IP/库名/表名"的格式备份数据
脚本:
#!/bin/bash
for db_name in zh wordpress
do
table_list=$(mysql -uroot -p123 -e "show tables from ${db_name};"|grep -v "Tables_in")
mkdir -p /backup/${db_name}
for table_name in ${table_list}
do
mysqldump -uroot -p123 ${db_name} ${table_name} >> /backup/${db_name}/${table_name}.sql
done
done
抓取blog的文章标题
目标博客:
https://www.cnblogs.com/alaska/default.html?page=1
需求:
1.批量获取博客的所有文章链接
2.过滤和整理出所有的文章标题
脚本:
#!/bin/bash
curl -s https://www.cnblogs.com/alaska/default.html?page=1 -o blog.html
PAGE_MAX=$(grep "page=" blog.html|sed -r 's#.*page=(.*)".*$#\1#g'|sort|tail -1)
echo "一共有${PAGE_MAX}"
for line in $(seq 1 ${PAGE_MAX})
do
curl -s https://www.cnblogs.com/alaska/default.html?page=${line} -o page_${line}.html
for num in $(awk '/postTitle2/{print NR}' page_${line}.html)
do
url=$(awk -F "\"" 'NR=='${num}'{print $4}' page_${line}.html )
title_line=$[ ${num} + 2 ]
title=$(sed -n "${title_line}"p page_${line}.html|awk '{print $1}')
echo -e "${title} \t ${url}" >> title.txt
done
done
json格式转换
原始文本:
[root@m-61 shell]# cat json.txt
aaa:111
bbb:222
ccc:333
转换为:
[root@m-61 shell]# bash json.sh
{
"data":[
{"aaa":"111"},
{"bbb":"222"},
{"ccc":"333"}
]}
#!/bin/bash
echo "{"
echo "\"data\":["
max_line=$(cat json.txt|wc -l)
sed -rn 's#(.*):(.*)#\{"\1":"\2"}\,#gp' json.txt|sed -r "${max_line}s#\,##g"
echo "]}"
#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
num=`cat 1.txt | wc -l`
v1=(`awk -F ":" '{print $1}' 1.txt`)
v2=(`awk -F ":" '{print $2}' 1.txt`)
echo -e '{\n"data":['
for (( i = 0; i < ${num}; i++ )); do
if [ ${i} != $[num - 1] ]; then
echo "{\"${v1[i]}\":\"${v2[i]}\"}",
else
echo "{\"${v1[i]}\":\"${v2[i]}\"}"
fi
done
echo ']}'
[root@m-61 shell]# cat json.sh
#!/bin/bash
echo '{'
echo '"data":['
max_line=$(cat json.txt|wc -l)
for i in $(seq 1 $(max_line))
do
if [ $i -lt $max_line ];then
echo "{\"$(awk -F: "NR==$i"'{print $1}' json.txt)\":\"$(awk -F: "NR==$i"'{print $2}' json.txt)\"}",
else
echo "{\"$(awk -F: "NR==$i"'{print $1}' json.txt)\":\"$(awk -F: "NR==$i"'{print $2}' json.txt)\"}"
fi
done
echo "]}"
]}
按范围输出文本
原始文本:
有文本如下:
1
2
3
4
5
6
7
8
9
10
11
12
需求:
每四行输出到一个文本,文件名按文本里第一行命名
#!/bin/bash
cat num.txt|xargs -n 4 > num_v2.txt
max_line=$(cat num_v2.txt|wc -l)
for num in $(seq 1 ${max_line})
do
sed -n "$num"p num_v2.txt|xargs -n 1 >> ${num}.txt
done
#!/bin/bash
for (( i = 0; i < 5; i++ )); do
echo $(cat num.txt|xargs -n 4|awk "NR==${i}"'{print}') > ${i}.txt
done
#!/bin/bash
max_line=$(cat num.txt|wc -l)
for i in $( seq 1 4 ${max_line} )
do
num=$[ ${i} + 3 ]
sed -n "$[i],${num}"p num.txt >> ${i}.txt
done
第6章 shell流程控制之while循环
1.while循环使用场景
1.for是明确知道要循环多少次,while可以在不知道要循环多少次的场景下使用
2.比如如果用户输入错了,可以尝试重新输入,而不是退出
3.比如除非用户输入了退出指令才退出,否则一直不退出
2.while循环基本语法
while 条件测试 #如果条件成立,则执行循环
do
循环执行的命令
done
3.举例
直到满足条件退出
#!/bin/bash
num=0
while [ ${num} -lt 10 ]
do
echo "num is ${num}"
num=$[ ${num} + 1 ]
done
从文件里读取数据
方法1:
exec < test.txt
while read line
do
echo $line
done
方法2:
while read line
do
echo $line
done < test.txt
方法3:
cat test.txt|while read line
do
echo $line
done
4.练习
计算器
需求:使用while输出如下格式
9*1 =9
8*2 =16
7*3 =21
6*4 =24
5*5 =25
4*6 =24
3*7 =21
2*8 =16
1*9 =9
脚本1:
#!/bin/bash
num=9
while [ ${num} -ge 1 ]
do
echo "$num * $num = $[ $num * $num ]"
num=$[ $num -1 ]
done
脚本2:
#!/bin/bash
a=9
b=1
while [ ${a} -ge 1 ]
do
echo "$a * $b = $[ $a * $b ]"
a=$[ $a -1 ]
b=$[ $b -1 ]
done
直到输对了才退出
需求:
1.提示用户输入账号
2.除非输入了root,否则一直提示输入
脚本:
#!/bin/bash
while [ "$user" != "root" ]
do
read -p "请输入root:" user
done
从文本里获取要创建的用户名:密码:uid:gid
#!/bin/bash
exec < name.txt
while read line
do
GROUP=$(echo ${line}|awk -F ":" '{print $1}')
GID=$(echo ${line}|awk -F ":" '{print $4}')
USER=$(echo ${line}|awk -F ":" '{print $1}')
UID=$(echo ${line}|awk -F ":" '{print $3}')
PASS=$(echo ${line}|awk -F ":" '{print $2}')
groupadd ${GROUP} -g ${GID}
useradd ${USER} -u ${UID} -g ${GID}
echo ${PASS}|passwd --stdin
done
猜数字游戏
需求
1.随机生成一个1-100的数字
2.要求用户输入的必须是数字
3.友好提示,如果用户输入的数字比随机数大,则提醒大了,否则提醒小了
4.只有输入正确才退出,输入错误就一直循环
5.最后统计猜了多少次
6期脚本:
需求: 猜数字大小
用户输入一个数字
如果大了,提示大了
如果小了,提示小了
提示完不退出,继续猜
如果猜中了,提示中奖了并退出
脚本如下:
#!/bin/bash
ok_num=$(echo $[$RANDOM%100 + 1])
read -p "please input num:" num
while [ "${num}" != "${ok_num}" ]
do
if [ "$num" -lt "$ok_num" ];then
echo "小了"
else
echo "大了"
fi
read -p "please input num:" num
done
echo "去领奖吧"
脚本:
#!/bin/bash
sj=$(echo $[$RANDOM%100 + 1])
count=0
while true
do
read -p "来下注吧,请输入整数: " num
count=$[ $count+1 ]
if [ ! -z $(echo ${num}|sed -r 's#[0-9]+##g') ];then
echo "你是zzy吗?"
continue
fi
if [ $num == $sj ];then
echo "您成功打爆了zzy的gt ${count}次! 正确数字为: $sj"
exit
fi
if [ $num -gt $sj ];then
echo "你输大了"
else
echo "你输小了"
fi
done
外挂脚本:
#!/bin/bash
#for方法
#for i in {1..100}
#do
# jieguo=$(bash while_v2.sh ${i})
# if [ "$jieguo" == "去找浩斌领奖吧" ];then
# echo "中奖数字为: ${i}"
# exit
# fi
#done
#while方法
num=0
jieguo=0
while [ "$jieguo" != "去找浩斌领奖吧" ]
do
jieguo=$(bash while_v2.sh ${num})
num=$[ $num + 1 ]
done
echo "$[ $num - 1 ]"
限制输错次数
#!/bin/bash
ok_num=10
num=1
while true
do
read -p "please input num:" input_num
if [ "$input_num" -eq ${ok_num} ];then
echo "你猜对了"
exit
else
echo "你输错了"
echo "你还有 $[ 3 - $num ] 次机会"
fi
if [ "$num" -eq 3 ];then
echo "你输错太多了"
exit
fi
num=$[ num + 1 ]
done
不退出的菜单
#!/bin/bash
while true
do
read -p "请输入您的选择:" num
case $num in
1)
echo "选择1"
;;
2)
echo "选择2"
;;
3)
echo "选择3"
;;
exit)
echo "bye"
exit
;;
*)
echo "选择1-3"
esac
done
跳板机脚本
#!/bin/bash
trap "" HUP INT QUIT TSTP
while true
do
echo "
===================
| 1.lb-5 |
| 2.lb-6 |
| 3.web-7 |
| 4.web-8 |
| 5.exit |
===================
"
read -p "请输入需要登陆的主机:" num
case $num in
1)
ssh root@10.0.0.5
;;
2)
ssh root@10.0.0.6
;;
3)
ssh root@10.0.0.7
;;
4)
ssh root@10.0.0.8
;;
5)
exit
;;
*)
continue
esac
done
第7章 shell流程控制之循环控制
1.应用场景
1.有些时候我们可能希望在满足特定条件的情况下立刻终止循环,即使循环还没结束
2.比如如果输错3次密码就强制退出,如果输入了退出关键里立刻退出等
2.break
2.1 break解释
结束当前的循环,但会继续执行循环之后所有的代码
2.2 break举例
#!/bin/bash
for i in {1..3}
do
echo "123"
break
echo "456"
done
echo "all is ok"
3.continue
3.1 continue解释
1.忽略本次循环剩余的代码,直接进入下次循环,直到循环结束
2.循环结束之后,继续执行循环以外的代码。
3.2 continue举例
#!/bin/bash
for i in {1..3}
do
echo "123"
continue
echo "456"
done
echo "all is ok"
4.exit
4.1 exit解释
遇到exit直接退出整个脚本,后面不管有多少命令都不执行
4.2 exit举例
#!/bin/bash
for num in {1..3}
do
echo "123"
exit
echo "456"
done
echo "all is ok"
第8章 shell函数
1.函数的作用
函数的作用就是将需要重复运行的代码抽象出来然后封装成一个函数,后续需要使用的时候只需要引用函数就可以了,而不需要每次都写重复的内容。
2.函数的定义和调用
2.1 定义函数的两种方法
第一种方法
start(){
command
}
第二种方法
function start(){
command
}
2.2 函数调用的方法
start(){
command
}
function stop(){
command
}
start
stop
3.函数的传参
3.1 函数传参介绍
1.用户执行脚本传递的位置参数和函数传递的参数事两回事
2.函数执行的时候需要将位置参数传递给函数,这样才会将参数带入函数执行。
3.2 举例
#!/bin/bash
fun1() {
case $2 in
+)
echo "$1 + $3 = $[ $1 + $3 ]"
;;
-)
echo "$1 + $3 = $[ $1 + $3 ]"
;;
x)
echo "$1 * $3 = $[ $1 * $3 ]"
;;
/)
echo "$1 + $3 = $[ $1 + $3 ]"
;;
*)
echo "bash $0 num1 {+|-|x|/} num2"
esac
}
fun1 $1 $2 $3
4.函数的练习
4.1 编写nginx管理脚本
#!/bin/bash
UAGE(){
echo "UAGE: bash $0 {start|stop|restart}"
}
start_nginx(){
echo "nginx is start"
}
stop_nginx(){
echo "nginx is stop"
}
case $1 in
start)
start_nginx
;;
stop)
stop_nginx
;;
restart)
stop_nginx
start_nginx
;;
*)
UAGE
esac
4.2 编写多极菜单
#!/bin/bash
#1级菜单
menu1(){
echo "
-----------------------------
1.Install Nginx
2.Install PHP
3.Install MySQL
4.Quit
-----------------------------
"
}
#2级菜单
menu2(){
echo "
-----------------------------
1.Install Nginx1.15
2.Install Nginx1.16
3.Install Nginx1.17
4.返回上一层
-----------------------------
"
}
#打印1级菜单
menu1
while true
do
#选择1级菜单
read -p "选择对应的数字:" num1
case $num1 in
1)
#打印2级菜单
menu2
while true
do
read -p "请选择您要安装的Nginx版本: " num2
case $num2 in
1)
echo "Install Nginx1.15 is OK!"
;;
2)
echo "Install Nginx1.16 is OK!"
;;
3)
echo "Install Nginx1.17 is OK!"
;;
4)
clear
menu1
break
;;
*)
continue
esac
done
;;
2)
echo "Install PHP"
;;
3)
echo "Install Mysql"
;;
4)
exit
;;
*)
continue
esac
done
4.3 多级菜单脚本
原始脚本:
#!/bin/bash
while true
do
echo -e "
1.Install Nginx
2.Install PHP
3.Quit"
read -p "please input num" num
case $num in
1)
while true
do
echo -e "
1.Install Nginx1.15
2.Install Nginx1.16
3.Install Nginx1.17
4.return"
read -p "please input num" num
case $num in
1)
echo "Nginx1.15 is installed"
break
;;
2)
echo "Nginx1.16 is installed"
break
;;
3)
echo "Nginx1.17 is installed"
break
;;
4)
break
;;
*)
echo "1-4"
esac
done
;;
2)
while true
do
echo -e "
1.Install php-5.5
2.Install php-5.7
3.Install php-7.2
4.return"
read -p "please input num" num
case $num in
1)
echo "php-5.5 is installed"
break
;;
2)
echo "php-5.7 is installed"
break
;;
3)
echo "php-7.2 is installed"
break
;;
4)
break
;;
*)
echo "1-4"
esac
done
;;
3)
exit
;;
*)
echo "1-3"
esac
done
函数脚本:
#!/bin/bash
menu(){
echo -e "
1.Install Nginx
2.Install PHP
3.mysql
4.Quit"
}
nginx(){
while true
do
echo -e "
1.Install Nginx1.15
2.Install Nginx1.16
3.Install Nginx1.17
4.return"
read -p "please input num" num
case $num in
1)
echo "Nginx1.15 is installed"
break
;;
2)
echo "Nginx1.16 is installed"
break
;;
3)
echo "Nginx1.17 is installed"
break
;;
4)
break
;;
*)
echo "1-4"
esac
done
}
php(){
while true
do
echo -e "
1.Install php-5.5
2.Install php-5.7
3.Install php-7.2
4.return"
read -p "please input num" num
case $num in
1)
echo "php-5.5 is installed"
break
;;
2)
echo "php-5.7 is installed"
break
;;
3)
echo "php-7.2 is installed"
break
;;
4)
break
;;
*)
echo "1-4"
esac
done
}
mysql(){
while true
do
echo -e "
1.Install mysql-5.5
2.Install mysql-5.7
3.Install mysql-7.2
4.return"
read -p "please input num" num
case $num in
1)
echo "mysql-5.5 is installed"
break
;;
2)
echo "mysql-5.7 is installed"
break
;;
3)
echo "mysql-7.2 is installed"
break
;;
4)
break
;;
*)
echo "1-4"
esac
done
}
main(){
while true
do
menu
read -p "please input num" num
case $num in
1)
nginx
;;
2)
php
;;
3)
mysql
;;
4)
exit
;;
*)
echo "1-3"
esac
done
}
main
4.3 编写跳板机脚本
#!/bin/bash
memu(){
echo"
===================
| 1.lb-5 |
| 2.lb-6 |
| 3.web-7 |
| 4.web-8 |
| 5.exit |
===================
"
trap "" HUP INT QUIT TSTP
while true
do
memu
read -p "请输入需要登陆的主机:" num
case $num in
1)
ssh root@10.0.0.5
;;
2)
ssh root@10.0.0.6
;;
3)
ssh root@10.0.0.7
;;
4)
ssh root@10.0.0.8
;;
5)
exit
;;
*)
continue
esac
done
综合练习-将用户登陆注册功能修改为函数版本
需求:
把ATM机的用户登陆注册用函数,case,while,continue实现所有功能
脚本:
#!/bin/bash
name_list=bank.txt
log=log.txt
time=$(date)
menu(){
echo "
===========
1.登陆
2.注册
===========
"
read -p "请选择需要的操作:" menu
}
check_login_name(){
read -p "请输入用户名:" name
grep -wo "${name}" ${name_list} >> /dev/null 2>&1
if [ $? != 0 ];then
echo "用户名不存在,请重新输入"
check_login_name
fi
}
check_login_pass(){
read -p "请输入密码:" passwd_input
passwd_user=$(awk -F":" "/^${name}\:/"'{print $2}' ${name_list})
#passwd_user=$(sed -rn "s#${name}:(.*)#\1#g"p bank.txt)
if [ ${passwd_input} == ${passwd_user} ];then
echo "登陆成功!"
echo "${time} ${name} 登陆成功!" >> ${log}
exit
else
echo "密码错误,请重新输入"
echo "${time} ${name} 登陆失败!" >> ${log}
check_login_pass
fi
}
check_regist_name(){
read -p "请输入注册用户名:" name
grep -wo "${name}" ${name_list} >> /dev/null 2>&1
if [ $? = 0 ];then
echo "用户名已存在,再选一个吧"
check_regist_name
fi
}
check_regist_pass(){
read -p "请输入密码:" passwd1
read -p "请再次输入密码:" passwd2
if [ ${passwd1} == ${passwd2} ];then
echo "${name}:${passwd1}" >> ${name_list}
if [ $? == 0 ];then
echo "注册成功,请登录"
echo "${time} ${name} 注册成功!" >> ${log}
main
else
echo "注册失败,请联系管理员"
echo "${time} ${name} 注册失败!" >> ${log}
exit
fi
else
echo "两次输入的密码不一致,请重新输入"
check_regist_pass
fi
}
main(){
while true
do
menu
case ${menu} in
1)
check_login_name
check_login_pass
;;
2)
check_regist_name
check_regist_pass
;;
*)
echo "请选择1-2的数字"
main
esac
done
}
main
综合练习-用户登录注册函数改写
#!/bin/bash
#定义登录函数
check_login(){
read -p "请输入用户名:" input_username
check_name=$(grep "^$input_username:" name.txt |wc -l)
if [ $check_name == 0 ];then
echo "账户名不存在"
exit
fi
read -p "请输入密码:" input_passwd
pass=$(awk -F: "/^${input_username}:/"'{print $2}' name.txt)
if [ $pass == $input_passwd ];then
echo "登录成功!"
else
echo "账号密码错误!"
exit
fi
}
#定义注册函数
check_regist(){
read -p "请输入用户名:" input_username
if [ -z "$input_username" ];then
echo "用户名不能为空,请重新输入"
exit
fi
check_format=$(echo $input_username|egrep '[^0-9a-Z]+'|wc -l )
if [ $check_format != 0 ];then
echo "输入的用户名不能包含特殊字符"
exit
fi
check_name=$(grep "^$input_username:" name.txt |wc -l)
if [ $check_name != 0 ];then
echo "账户名已存在,再选一个吧"
exit
fi
input_username_lenth=$(echo ${input_username}|wc -L)
if [ "$input_username_lenth" -lt 4 -o "$input_username_lenth" -gt 8 ];then
echo "注册的账号名小于4为并且不能大于8位"
exit
fi
read -p "请输入密码:" input_passwd
check_format=$(echo $input_passwd|egrep '[^0-9a-Z]+'|wc -l )
if [ $check_format != 0 ];then
echo "输入的密码不能包含特殊字符"
exit
fi
input_passwd_lenth=$(echo $input_passwd|wc -L)
if [ "$input_passwd_lenth" -le 4 -o "$input_passwd_lenth" -gt 8 ];then
echo "注册的密码不能小于4位并且不能大于8位"
exit
fi
read -p "请再次输入密码:" input_passwd_check
if [ "$input_passwd" != "$input_passwd_check" ];then
echo "两次输入的密码不一致"
exit
fi
echo "${input_username}:${input_passwd}" >> name.txt
echo "注册成功!"
}
#定义菜单函数
menu(){
echo -e '
===========
1.注册
2.登录
==========='
read -p "请输入1-2:" num
}
#定义主函数
main(){
menu
case $num in
1)
check_login
;;
2)
check_regist
;;
*)
echo "请输入1-2"
esac
}
#调用主函数
main
综合练习-检查服务端口是否开启
exec < /scripts/ip-ports.txt
while read line
do
count=0
nc -w 10 -z $line >> /tmp/ip.log 2>&1
if [ $? -ne 0 ];then
for i in {1..3}
do
nc -w 10 -z $line >> /tmp/ip.log 2>&1
if [ $? -ne 0 ];then
count=$[ ${count}+1 ]
else
break
fi
if [ $count -eq 3 ];then
sleep 3
echo "民银牛app生产服务器${line}连接不通"|/usr/local/bin/mailx -v -s "test" 1214131982@qq.com >> /tmp/cron.log 2>&1
fi
done
fi
done
第9章 shell数组
1.数组介绍
数组主要是用来存值,只不过可以存储多个值。
2.数组分类
普通数组: 当一个数组定义多个值,需要取值时,只能通过整数来 取值 0 1 2 3 4 5
关联数组:他可以自定义索引名称,当需要取值时,只需要通过 数组的名称[索引] ---> 值
3.数组的赋值与取值
不用数组取内容
#!/bin/bash
name_list="user1 user2 user3 user4"
num=0
num2=0
for i in ${name_list}
do
num=$[ $num + 1 ]
if [ "$num" == "3" ];then
echo $i
fi
done
for i in ${name_list}
do
num2=$[ $num2 + 1 ]
if [ "$i" == "user3" ];then
echo $num2
fi
done
普通数组赋值
[root@m-61 ~/scripts]# books=(linux nginx shell)
关联数组赋值
注意: 必须先声明这是关联数组
[root@m-61 ~/scripts]# declare -A info
方法1:(数组名=( [索引1]=值1 [索引2]=值2) )
[root@m-61 ~/scripts]# info=([index1]=linux [index2]=nginx [index3]=docker [index4]='bash shell')
[root@m-61 ~/scripts]# echo ${info[@]}
bash shell linux nginx docker
[root@m-61 ~/scripts]# echo ${!info[@]}
index4 index1 index2 index3
方法2:( 数组名[索引]=变量值 )
[root@m-61 ~/scripts]# info2[index1]=value1
[root@m-61 ~/scripts]# info2[index2]=value2
[root@m-61 ~/scripts]# info2[index3]=value3
取单个值
[root@m-61 ~/scripts]# echo ${books[0]}
linux
[root@m-61 ~/scripts]# echo ${books[1]}
nginx
[root@m-61 ~/scripts]# echo ${books[2]}
shell
[root@m-61 ~/scripts]# echo ${info2[index1]}
value1
[root@m-61 ~/scripts]# echo ${info2[index2]}
value2
[root@m-61 ~/scripts]# echo ${info2[index3]}
value3
取所有值
[root@m-61 ~/scripts]# echo ${books[@]}
linux nginx shell
[root@m-61 ~/scripts]# echo ${info2[@]}
value1 value2 value3
取出所有索引
[root@m-61 ~/scripts]# echo ${!books[@]}
0 1 2
[root@m-61 ~/scripts]# echo ${!info2[@]}
index1 index2 index3
数组取值小结
echo ${!array[*]} #取关联数组所有键
echo ${!array[@]} #取关联数组所有键
echo ${array[*]} #取关联数组所有值
echo ${array[@]} #取关联数组所有值
echo ${#array[*]} #取关联数组长度
echo ${#array[@]} #取关联数组长度
4.数组的遍历
需求1:统计/etc/passwd里每个用户shell出现的次数
脚本:
[root@m-61 ~/scripts]# cat set.sh
#!/bin/bash
declare -A shell_num
exec < /etc/passwd
while read line
do
shell=$(echo $line | awk -F ":" '{print $NF}')
#要统计谁,就将谁作为索引,然后让其自增
let shell_num[$shell]++
done
#批量取值
for item in ${!shell_num[@]}
do
echo "索引是: $item 出现的次数为: ${shell_num[$item]}"
done
脚本:
#!/bin/bash
awk -F: '{print $NF}' /etc/passwd > /root/passwd.txt
declare -A passwd #自定义关联组
for pass in $(cat /root/passwd.txt)
do
passwd[$pass]=$[ ${passwd[$pass]} + 1 ] #组名加自身键值初始为0加1
done
for ps in $(echo ${!passwd[*]}) #输出所有键值
do
echo "${ps} ${passwd[$ps]}"
done
执行结果:
[root@m-61 ~/scripts]# bash set.sh
索引是: /sbin/nologin 出现的次数为: 18
索引是: /bin/sync 出现的次数为: 1
索引是: /bin/bash 出现的次数为: 1
索引是: /sbin/shutdown 出现的次数为: 1
索引是: /sbin/halt 出现的次数为: 1
需求2: 使用数组统计Nginx日志排名前10IP
脚本:
#!/bin/bash
declare -A IP
exec < bbs.xxxx.com_access.log
while read line
do
num=$(echo $line | awk '{print $1}')
#要统计谁,就将谁作为索引,然后让其自增
let IP[$num]++
done
#批量取值 10.0.0.61 10.0.0.6
for item in ${!IP[@]}
do
echo "${item} ${IP[$item]}"
done
如果使用AWK处理,效率要比数组高很多倍
time awk '{Ip[$1]++} END { for (item in Ip) print Ip[item],item }' bbs.xxxx.com_access.log
5.数组练习题
需求:
文本内容:
a
b
c
1
2
3
处理后结果
1 a
2 b
3 c
脚本1:
#!/bin/bash
num=$[ $(cat num.txt|wc -l)/2 ]
S1=($(sed -n "1,$num"p num.txt))
S2=($(sed -n "$[$num+1],\$"p num.txt))
for i in $(seq 0 $[$num-1])
do
echo ${S2[$i]} ${S1[$i]}
done
脚本2:
#!/bin/bash
num=$[ $(cat num.txt|wc -l)/2 ]
for i in $(seq 1 $num)
do
S1=$(sed -n "$i"p num.txt)
S2_num=$[ $i + $num ]
S2=$(sed -n "$S2_num"p num.txt)
echo ${S2} ${S1}
done