day054-058-Shell编程

38次阅读
没有评论

Shell编程

一、Shell介绍-day054

1.shell学习大纲
  1. 入门、规范
  2. shell执行方式
  3. 变量基础
  4. 变量子串
  5. 核心位置变量
  6. 数值比对
  7. 字符串比对
  8. 文件判断
  9. if判断
  10. case语句
  11. for循环
  12. while循环
  13. 流程控制 exit continue break
  14. 函数
  15. 数组
2.Shell作用
  • 安装系统 kickstart cobbler
  • 操作系统优化 写入shell脚本
  • 部署业务、安装服务 写入shell脚本
  • 变更配置、代码上线结合shell脚本
  • 监控 shell取值
  • shell做监控+定时任务结合
  • 辅助程序正常运行+定时任务
  • 日志统计分析、日志切割
  • 业务相关功能
3.学习Shell脚本必会技能
  • linux系统命令
  • awk sed grep命令
  • vim编辑器
4.学好Shell编程

1.基础扎实 系统命令 三剑客 vim 变量 表达式
2.多练、课上的案例 熟能生巧
3.看的懂脚本、在基础上修改、扩展增加一些功能
4.切忌拿来即用、需要理解变成自己的
5.编程思维
6.完整的书籍,笔记做好


5.什么是shell

shell命令解释器,默认centos kylin ubt缺省shell为bash (笔试题)
用户输入命令–>给bash命令解释器–>翻译给内核–>内核驱动硬件完成操作-返回给bash–>返回给用户

交互式shell和非交互式shell(命令行和脚本运行)

交互式模式就是shell等待用户的输入,并且执行用户提交的命令。这种模式被称作交互式是因为shell与用户进行交互。这种模式也是大多数用户非常熟悉的:登录、执行一些命令、签退。当用户签退后,shell也终止了。

shell也可以运行在另外一种模式:非交互式模式。在这种模式下,shell不与用户进行交互,而是读取存放在文件中的命令,并且执行它们。当它读到文件的结尾,shell也就终止了。

#/bin/bash和/bin/sh
[root@shell ~]# ll /bin/bash
-rwxr-xr-x 1 root root 1162856 Aug 26  2022 /bin/bash
[root@shell ~]# ll /bin/sh
lrwxrwxrwx 1 root root 4 Aug 26  2022 /bin/sh -> bash
6.编程语言
shell python解释型语言。
7.Shell脚本规范
1.脚本开头写解释器 #!/bin/bash或者#!/bin/sh
2.脚本名称必须以.sh结尾
3.脚本中语法、功能注释使用中文或英文
4.脚本语法一次写完
5.成对符号一些写完
6.符号必须是英文
8.第一个Shell脚本
#输出世界你好
[root@shell ~]# cat test.sh
#!/bin/bash                     # 指定解释器 默认就是bash执行

#输出世界你好
echo "Hello World!!"
[root@shell ~]# sh test.sh
Hello World!!
9.Shell脚本执行方式
常用执行方式:
1.使用解释器执行 sh  bash、不需要脚本有x执行权限
2.使用路径方式执行、必须给文件x执行权限
3.使用. 或者source执行
其他方式:
1.bash < test.sh 
2.cat test.sh |bash
案例1:使用解释器执行 sh bash、不需要脚本有x执行权限
[root@shell ~]# bash test.sh
Hello World!!
[root@shell ~]# sh test.sh
Hello World!!
[root@shell ~]# sh /root/test.sh
Hello World!!
案例2:使用路径方式执行、必须给文件x执行权限
#赋予执行权限
[root@shell ~]# chmod +x test.sh 
[root@shell ~]# ll test.sh 
-rwxr-xr-x 1 root root 54 Jun  1 10:33 test.sh

绝对路径:
[root@shell ~]# /root/test.sh
Hello World!!

相对路径:
[root@shell ~]# ./test.sh 
Hello World!!
案例3:使用. 或者source执行
[root@shell ~]# . test.sh
Hello World!!
[root@shell ~]# source test.sh
Hello World!!
案例4:其他执行脚本的方式
[root@shell ~]# bash < test.sh 
Hello World!!

[root@shell ~]# cat test.sh |bash
Hello World!!
Usage: bash [start|stop|restart|reload|status]
小结

三种执行脚本方式区别:

  • 使用bash或者路径方式都是在子shell中执行。

  • . 和 source都是在父shell中执行。

  • 父shell: 登录系统后所在的位置就是父shell、不能继续子shell的信息、变量

  • 子shell: bash回车产生了子shell、继续父shell衣钵、信息变量,在使用bash执行脚本使用子shell

二、变量

1.变量
什么是变量?

使用一个固定的值、来表示一串不固定的值称为变量。

dir=/etc/sysconfig/network

变量名称定义规范:
1.见名知其意
2.等号两端不允许有空格
3.名字不能以数字开头、可用下划线和字母开头
4.不连续的字符串需要使用引号或者双引号
5.大驼峰、小驼峰、大写、小写

Name=oldboy
Name_Age=xxx
name_Age=xxx
NAME=oldboy   # 系统都是全大写
name=oldboy
变量值的定义

1.数字,必须是连续的,如果不连续需要加引号

age=123
age='1 2 3'

​ 2.字符串,必须是连续的,不连续需要加引号

[root@shell ~]# name=oldboy
[root@shell ~]# name='o d b'

不加引号、单引号、双引号区别
不加和双引号都可以解析变量
单引号所见即所得、不能解析变量

[root@shell ~]# a=hehe
[root@shell ~]# name='$a'
[root@shell ~]# echo $name
$a
[root@shell ~]# name=$a
[root@shell ~]# echo $name
hehe
[root@shell ~]# name="$a"
[root@shell ~]# echo $name
hehe

​ 3.命令

两种方法:
使用反引号
使用$()
也可以用字符串的方式定义!

#案例1.定义命令
[root@shell ~]# dir=`hostname`_`hostname -I|awk '{print $1}'`
[root@shell ~]# echo $dir
shell_10.0.0.7
[root@shell ~]# echo $name
hehe
[root@shell ~]# dir=`hostname`_`hostname -I|awk '{print $1}'`_$name
[root@shell ~]# echo $dir
shell_10.0.0.7_hehe

[root@shell ~]# dir=`hostname`
[root@shell ~]# echo $dir
shell
[root@shell ~]# dir=$(hostname)
[root@shell ~]# echo $dir
shell

#案例2.将命令作为字符串来定义
[root@shell ~]# dir='cd /etc/sysconfig/network-scripts'
[root@shell ~]# echo $dir
cd /etc/sysconfig/network-scripts
[root@shell ~]# $dir
[root@shell network-scripts]# 

#案例3.时间定义反引号和字符串的区别
[root@shell ~]# TIME=`date +%F-%H-%M-%S`
[root@shell ~]# echo $TIME
2026-06-01-11-41-00

[root@shell ~]# TIME='date +%F-%H-%M-%S'
[root@shell ~]# echo $TIME
date +%F-%H-%M-%S
[root@shell ~]# $TIME
2026-06-01-11-44-02
变量分类
变量分类
全局变量: 全局生效 针对所有用户及shell生效 类似国法
局部变量: 局部生效 只对当前的shell生效    类似家规

全局变量: 系统定义的 PATH PS1  写入/etc/profile
局部变量: 我们自定义、一般定义到脚本中。

全局变量定义: 使用export+变量 写入/etc/profile
局域变量定义: 直接定义 name=oldboy 写入脚本中

加export和不加export的区别
只对当前父 shell 以及他下面的子 shell 有效,对其他父 shell 不生效
不加export只让当前的shell生效

案例1.不加export、只对当前的shell生效
[root@shell ~]# a=hehe
[root@shell ~]# echo $a
hehe
[root@shell ~]# bash
[root@shell ~]# echo $a

[root@shell ~]# exit
exit

案例2.加export
[root@shell ~]# export b=aaaaaaaaaaa
[root@shell ~]# echo $b
aaaaaaaaaaa
[root@shell ~]# bash
[root@shell ~]# echo $b
aaaaaaaaaaa
[root@shell ~]# cat test.sh 
#!/bin/bash

#输出世界你好
echo "Hello World!!"

echo $b
[root@shell ~]# sh test.sh 
Hello World!!
aaaaaaaaaaa
2.核心位置变量
$0    # 表示脚本的名称
$n    # 表示脚本传参第n个参数,n为数字
$#    # 表示脚本传参的总个数
$?    # 表示上一条命令执行结果,0为成功,非0失败

$!    # 表示调用上一个在后台执行的脚本PID
$$    # 获取脚本的PID号
$*    # 获取脚本传参所有参数
$@    # 获取脚本传参所有参数
$_    # 获取脚本的最后一个参数 类似esc .
案例1:$0
[root@shell ~]# cat test.sh
#!/bin/bash

#输出世界你好
echo "Hello World!!"

echo $0
[root@shell ~]# sh test.sh
Hello World!!
test.sh

#带路径,脚本名称也带路径
[root@shell ~]# /root/test.sh 
Hello World!!
/root/test.sh
案例2:$n
[root@shell day01]# cat test.sh 
#!/bin/bash
name=$1
age=$2

echo 姓名: $name
echo 年龄: $age

[root@shell day01]# cat test.sh 
#!/bin/bash
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10}

[root@shell day01]# sh test.sh {a..z}
a b c d e f g h i j

[root@shell day01]# dir=oldboy
[root@shell day01]# echo $dir
oldboy
[root@shell day01]# 
[root@shell day01]# 
[root@shell day01]# test=$dir_`hostname`
[root@shell day01]# echo $test
shell
[root@shell day01]# echo $dir_

[root@shell day01]# test=${dir}_`hostname`
[root@shell day01]# echo $test
oldboy_shell

#[root@shell day01]# 金庸新 著
案例3:$
[root@shell day01]# cat test.sh 
#!/bin/bash
[ $# -ne 2 ] && echo "请输入2个参数" && exit
echo name=$1 
echo age=$2
[root@shell day01]# sh test.sh a
请输入2个参数
[root@shell day01]# sh test.sh a b c
请输入2个参数
[root@shell day01]# sh test.sh a 123
name=a
age=123
案例4:$?
[root@shell day01]# cat ping.sh
#!/bin/bash
ping -c1 -W1 $1
echo $?

[root@shell day01]# cat ping.sh
#!/bin/bash
ping -c1 -W1 $1 &>/dev/null
[ $? -eq 0 ] && echo 网络正常 || echo 网络异常
[root@shell day01]# sh ping.sh www.sina.com
网络正常
[root@shell day01]# sh ping.sh www.sinaaaaaa.com
网络异常
案例5:$!输出上一个在后台脚本的PID
nohup xxx &
screen -S xx

[root@shell day01]# sh test.sh &
[1] 549565

[root@shell day01]# echo $!
549565
[root@shell day01]# ps axu|grep test.sh
root      549565  0.0  0.3 213772  3208 pts/0    S    15:55   0:00 sh test.sh
root      549573  0.0  0.0 213272   888 pts/0    S+   15:55   0:00 grep test.sh
[root@shell day01]# kill -9 $!
案例6:$$获取脚本PID号
[root@shell day01]# cat test.sh 
#!/bin/bash
echo $$  > /tmp/nginx.pid 
sleep 60
[ $# -ne 2 ] && echo "请输入2个参数" && exit
echo name=$1 
echo age=$2
案例7:$* $@接收脚本所有的传参
3.脚本传参
  • 三种方式:

    • 方法1.直接传参

    • 方法2.赋值传参

    • 方法3.read读入

案例1:直接传参
[root@shell day01]# cat env.sh
#!/bin/bash

echo $1
[root@shell day01]# sh env.sh

[root@shell day01]# sh env.sh a
a

[root@shell day01]# cat env.sh 
#!/bin/bash

echo $1  $2
[root@shell day01]# sh env.sh  a b
a b

[root@shell day01]# cat env.sh
#!/bin/bash

echo name=$1
echo age=$2
[root@shell day01]# sh env.sh old 123
name=old
age=123

[root@shell day01]# cat env.sh
#!/bin/bash

echo "name=$1  age=$2"
[root@shell day01]# sh env.sh old 123
name=old  age=123

[root@shell day01]# cat ping.sh 
#!/bin/bash

ping -c1 -W1 $1
[root@shell day01]# sh ping.sh www.sina.com
PING spool.grid.sinaedge.com (123.125.107.39) 56(84) bytes of data.
64 bytes from 123.125.107.39 (123.125.107.39): icmp_seq=1 ttl=128 time=4.96 ms

--- spool.grid.sinaedge.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 4.956/4.956/4.956/0.000 ms
案例2:赋值传参
[root@shell day01]# cat test.sh
#!/bin/bash
name=$1
age=$2

echo 姓名: $name
echo 年龄: $age
[root@shell day01]# sh test.sh
姓名:
年龄:
[root@shell day01]# sh test.sh a 123
姓名: a
年龄: 123

[root@shell day01]# cat ping.sh
#!/bin/bash
url=$1
ping -c1 -W1 $url
案例3:read读入
[root@shell day01]# cat read.sh 
#!/bin/bash

read -p "请输入姓名和年龄: " name age

echo "姓: " $name
echo "年龄: " $age
[root@shell day01]# sh read.sh
请输入姓名和年龄: a 123
姓:  a
年龄:  123

[root@shell day01]# cat read.sh
#!/bin/bash

read -p "请输入姓名: " name
read -p "请输入年龄: " age

echo "姓: " $name
echo "年龄: " $age
[root@shell day01]# sh read.sh
请输入姓名: old
请输入年龄: 123
姓:  old
年龄:  123

[root@shell day01]# cat read.sh 
#!/bin/bash

read -p "请输入姓名: " name
read -p "请输入年龄: " age
read -s -p  "请输入银行卡密码: " pass
echo -e "n"

echo "姓: " $name
echo "年龄: " $age
echo "密码: " $pass

[root@shell day01]# echo -e "oldboyntest"
oldboy
test
[root@shell day01]# echo -e "oldboyttest"
oldboy  test
4.重点总结
1.给你一台服务器你对它的操作流程是什么? #RAID 网络 系统 服务 业务 监控 
2.shell规范
3.shell必会技能 命令、三剑客、vim
4.执行shell脚本方式
bash sh
绝对路径/相对路径 必须给x执行权限
source 或者 .执行 . test.sh 
5.三种执行脚本方式的区别
前两个都是调用子shell执行,source和点都是在父shell中直接执行

6.变量
全局变量: 环境变量 /etc/profile
局部变量: 普通变量 脚本中

永久变量 写入文件
临时变量 直接在命令行定义 退出失效

定义变量:
名称的定义: 下划线、字母、数字的组合,不能以数字开头,等号两端不能有空格
值的定义: 不连续使用引号
1.连续的数字
age=2342
2.连续的字符串
name=oldboy

3.命令定义
dir=`hostname`
dir=$(hostname)

dir=hostname
$dir

不加引号和双引号解析变量、单引号不解析变量

export 可以让所有的shell生效、经常在全局定义在/etc/profile

7.脚本传参
直接传参
赋值传参
read读入 
   read -p 'xxxx' name
   read -s -p 'xxx' pass  隐藏密码

8.核心位置变量
$0
$n  $1 $2 $3
$# 传参的个数
$?

$$
$!
$*
$@

下次内容:
变量子串
数值运算
整数比对
字符串比对
文件判断
正则

三、表达式-day055

1.变量子串
01.子串长度
wc -L   #统计文件中最长字符串长度
awk '{print length}'
expr length
${#name}

案例1.统计字符串长度

[root@shell day02]# echo oldboy|wc -L
6

案例2.统计文件中最长字符串的长度

[root@shell day02]# cat 1.txt 
abc
adcde
a
123
[root@shell day02]# cat 1.txt |wc -L
5

案例3.使用awk统计每行的长度 了解

`竖着`
[root@shell day02]# cat 1.txt | awk '{print length}'
3
5
1
3
`横着`
[root@shell day02]# echo aa bb cdefg|xargs -n1
aa
bb
cdefg
[root@shell day02]# echo aa bb cdefg|xargs -n1|awk '{print length}'
2
2
5

案例4.使用awk循环统计长度

[root@shell day02]# echo aa abc cdefg|awk '{for(i=1;i<=NF;i:)print i}'
1
2
3
[root@shell day02]# echo aa abc cdefg|awk '{for(i=1;i<=NF;i++)print $i}'
aa
abc
cdefg
[root@shell day02]# echo aa abc cdefg|awk '{for(i=1;i<=NF;i++)print length($i) }'
2
3
5

案例5.使用expr统计长度

[root@shell day02]# expr length oldboy
6

案例6.使用子串方式统计

[root@shell day02]# name=oldboy
[root@shell day02]# echo ${#name}
6

案例7.笔试题:统计 I am oldboy I am 18 字符串长度小于3的字符串

#方法1:使用for循环
`循环遍历`
[root@shell day02]# cat count.sh 
#!/bin/bash
for i in I am oldboy I am 18
do
    echo $i
done
[root@shell day02]# sh count.sh 
I
am
oldboy
I
am
18
`统计长度`
[root@shell day02]# cat count.sh 
#!/bin/bash
for i in I am oldboy I am 18
do
    echo ${#i}
done
[root@shell day02]# sh count.sh 
1
2
6
1
2
2
`输出小于3的字符串`
[root@shell day02]# cat count.sh 
#!/bin/bash
for i in I am oldboy I am 18
do
    [ ${#i} -lt 3 ] && echo $i
done
[root@shell day02]# sh count.sh 
I
am
I
am
18

#方法2:使用awk判断
[root@shell day02]# echo I am oldboy I am 18|xargs -n1|awk '{if(length<3)print $i}'
I
am
I
am
18

#方法3:使用awk循环判断
[root@shell day02]# echo I am oldboy I am 18|awk '{for(i=1;i<=NF;i++)if(length($i)<3)print $i}'
I
am
I
am
18
02.子串删除

从前往后${url#} ${url##}

从后往前${url%} ${url%%}

#从前往后匹配删除使用#,贪婪匹配使用##
[root@shell day02]# echo ${url}
www.sina.com
[root@shell day02]# echo ${url#www}
.sina.com
[root@shell day02]# echo ${url#www.sina.}
com
[root@shell day02]# echo ${url#*.}
sina.com
[root@shell day02]# echo ${url#*.*.}
com
[root@shell day02]# echo ${url##*.}
com

#从后往前删除 使用%
[root@shell day02]# echo ${url%.comm}
www.sina.com
[root@shell day02]# echo ${url%.com}
www.sina
[root@shell day02]# echo ${url%%.*}
www

注意语法冲突
[root@shell day02]# a=24%
[root@shell day02]# echo $a
24%
[root@shell day02]# echo ${a%%}
24%
[root@shell day02]# echo ${a%%}
24
03.子串替换

替换使用/ 贪婪使用//

[root@shell day02]# echo ${url/w/W}
Www.sina.com
[root@shell day02]# echo ${url//w/W}
WWW.sina.com
[root@shell day02]# echo ${url/www/a}
a.sina.com
[root@shell day02]# echo ${url/www.sina/a}
a.com
2.数值运算
运算方式 支持整数 支持小数
expr ✅ 是 ❌ 否
$[] ✅ 是 ❌ 否
$(()) ✅ 是 ❌ 否
let ✅ 是 ❌ 否
bc ✅ 是 ✅ 是
awk ✅ 是 ✅ 是

expr、$[]、$(())、let 只能算:整数(加减乘除取余)

`基础算术运算符`
+   加
-   减
*   乘
/   除
%   取余
^   幂运算
`比较运算符`
==  等于
!=  不等于
>   大于
<   小于
>=  大于等于
<=  小于等于
`逻辑运算符`
&&   逻辑与(并且)
||   逻辑或(或者)
!    逻辑非(取反)
`赋值运算`
=    赋值
+=   加等于
++   自增 +1
`文本匹配`
~    匹配正则
!~   不匹配正则
01.expr运算
[root@shell day02]# expr 1+1
1+1
[root@shell day02]# expr 1 + 1
2
[root@shell day02]# expr 2 + 2
4
[root@shell day02]# expr 1 + 1
2
[root@shell day02]# expr 1 - 1
0
[root@shell day02]# expr 1 * 1
1
[root@shell day02]# expr 10 / 10
1
[root@shell day02]# expr 10 / 10 + 5
6
[root@shell day02]# expr 10 / 10 + 5 - 2
4
[root@shell day02]# expr 10 % 10
0
02.$[]
[root@shell day02]# echo $[1+1]
2
[root@shell day02]# echo $[10-10]
0
[root@shell day02]# echo $[10*10]
100
[root@shell day02]# echo $[10/10]
1
[root@shell day02]# echo $[10/10+2]
3
[root@shell day02]# echo $[10/10+2*6]
13
[root@shell day02]# echo $[10%3]
1
03.$(())
[root@shell day02]# echo $((10+10))
20
[root@shell day02]# echo $((10-10))
0
[root@shell day02]# echo $((10*10))
100
[root@shell day02]# echo $((10/10))
1
[root@shell day02]# echo $((10/10+5))
6
[root@shell day02]# echo $((10%3))
1
4.let运算

单独自增:i++和++i没区别

参与赋值/打印:

i++ → 先拿旧值,再加 1

++i → 先加 1,再拿新值

unset   #取消变量
b++==b=b+1

[root@shell day02]# unset a
[root@shell day02]# let a=a+1
[root@shell day02]# echo $a
1
[root@shell day02]# let a=a+1
[root@shell day02]# echo $a
2

[root@shell day02]# let i++
[root@shell day02]# echo $i
1

[root@shell day02]# num1=10
[root@shell day02]# num2=10
[root@shell day02]# let a=$num1+$num2
[root@shell day02]# echo $a
20

[root@shell day02]# cat a.sh 
for i in a b c d
do
    let ++a
    let b++
done
echo 当前总共循环了 $a 次
echo 当前总共循环了 $b 次
[root@shell day02]# sh a.sh 
当前总共循环了 4 次
当前总共循环了 4 次

#注意如果有变量i++ ++i不同的地方
[root@shell day02]# a=1
[root@shell day02]# b=1
[root@shell day02]# let c=a++       # 先赋值后运算
[root@shell day02]# let d=++b       # 先运算后赋值
[root@shell day02]# echo $c
1
[root@shell day02]# echo $d
2

[root@shell day02]# echo $a
2
[root@shell day02]# echo $b
2

变量自己:i++ 和 ++i 最终都 +1,完全一样
赋值给别人:
i++ → 返回旧值
++i → 返回新值
05.bc数值运算
[root@shell day02]# echo 1+1|bc
2
[root@shell day02]# echo 1-1|bc
0
[root@shell day02]# echo 1*10|bc
10
[root@shell day02]# echo 100/10|bc
10
[root@shell day02]# echo 10^10|bc
10000000000
[root@shell day02]# echo 10%3|bc
1
[root@shell day02]# echo 10/3|bc
3
[root@shell day02]# echo 100-10.5|bc
89.5
06.awk
[root@shell day02]# awk 'BEGIN{print 10+10}'
20
[root@shell day02]# awk 'BEGIN{print 10-10}'
0
[root@shell day02]# awk 'BEGIN{print 10*10}'
100
[root@shell day02]# awk 'BEGIN{print 10/10}'
1
[root@shell day02]# awk 'BEGIN{print 10/10.4}'
0.961538
[root@shell day02]# awk 'BEGIN{print 10.3+10.4}'
20.7
[root@shell day02]# awk 'BEGIN{print 10/3}'
3.33333
[root@shell day02]# awk 'BEGIN{print 2^2}'
4
[root@shell day02]# awk 'BEGIN{print 2^2-2}'
2

案例.三种传参方式写一个计算器

直接传参
赋值
read
sh count.sh 10 10
10+10=20
10-10=0
...
`直接传参`
[root@shell day02]# cat count.sh 
#!/bin/bash
echo $1+$2=$[$1+$2]
echo $1-$2=$[$1-$2]
echo $1*$2=$[$1*$2]
echo $1/$2=$[$1/$2]
[root@shell day02]# sh count.sh 10 10
10+10=20
10-10=0
10*10=100
10/10=1

`赋值传参`
[root@shell day02]# sh count.sh 10 + 10
10+10=20
[root@shell day02]# sh count.sh 10 - 10
10-10=0
[root@shell day02]# sh count.sh 10 * 10
10*10=100
[root@shell day02]# sh count.sh 10 / 10
10/10=1

`read读入`
[root@shell day02]# cat count.sh 
#!/bin/bash
read -p "请输入值 运算符 值:" num1 ss num2
echo $num1$ss$num2=$[$num1 $ss $num2]
[root@shell day02]# sh count.sh 
请输入值 运算符 值:10 + 10
10+10=20
[root@shell day02]# sh count.sh 
请输入值 运算符 值:10 * 10   
10*10=100
3.整数比较
语法结构:
        语法1:test 10 -eq 10
        语法2:[ 10 -eq 10 ]
写法 用途 比较符
test 标准 test -eq/-gt/-a/-o
[ ] 标准 test -eq/-gt/-a/-o
[[ ]] 全能判断 ><==!=(数值)、==*(通配)、=~(正则) && ||(逻辑)
(( )) 纯算术 ><==
符号 英文全称 含义 超好记
-eq equal 等于 equal
-ne not equal 不等于 not equal
-gt greater than 大于 greater than
-ge greater equal 大于等于 greater equal
-lt less than 小于 less than
-le less equal 小于等于 less equal
-a and 并且
-o or 或者
01.示例
`-eq`
[root@shell day02]# test 10 -eq 10 && echo 成立 || echo 不成立
成立
[root@shell day02]# [ 10 -eq 10 ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ 10 -eq 10 ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ 10 == 10 ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# (( 10 == 10 )) && echo 成立 || echo 不成立
成立

`-ne`
[root@shell day02]# test 10 -ne 10 && echo 成立 || echo 不成立
不成立
[root@shell day02]# [ 10 -ne 10 ] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 10 -ne 10 ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 10 != 10 ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# (( 10 != 10 )) && echo 成立 || echo 不成立
不成立

`-gt`
[root@shell day02]# test 10 -gt 10 && echo 成立 || echo 不成立
不成立
[root@shell day02]# [ 10 -gt 10 ] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 10 -gt 10 ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 10 > 10 ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# (( 10 > 10 )) && echo 成立 || echo 不成立
不成立

`-ge`
[root@shell day02]# test 10 -ge 10 && echo 成立 || echo 不成立
成立
[root@shell day02]# [ 10 -ge 10 ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ 10 -ge 10 ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# (( 10 >= 10 )) && echo 成立 || echo 不成立
成立

`-lt`
[root@shell day02]# test 10 -lt 10 && echo 成立 || echo 不成立
不成立
[root@shell day02]# [ 10 -lt 10 ] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 10 -lt 10 ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 10 < 10 ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# (( 10 < 10 )) && echo 成立 || echo 不成立
不成立

`-le`
[root@shell day02]# test 10 -le 10 && echo 成立 || echo 不成立
成立
[root@shell day02]# [ 10 -le 10 ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ 10 -le 10 ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# (( 10 <= 10 )) && echo 成立 || echo 不成立
成立

`-a`
[root@shell day02]# [ 10 -eq 10 -a 10 -ne 11 ] && echo 成立 || echo 不成立
成立

`-o`
[root@shell day02]# [ 10 -eq 10 -o 10 -ne 10 ] && echo 成立 || echo 不成立
成立

#表达式中支持命令和变量
[root@shell day02]# num1=10
[root@shell day02]# num2=10
[root@shell day02]# [ $num1 -eq $num2 ] && echo 成立 || echo不成立
成立
案例1:判断磁盘使用率
1.取值
[root@shell day02]# df -h|awk '/sda3/{print $(NF-1)}'
10%

2.判断
方式1:
[root@shell day02]# [ $(df -h|awk '/sda3/{print $(NF-1)}'|sed 's#%##g') -eq 10 ] && echo 成立 || echo 不成立
成立

方式2:先赋值
[root@shell day02]# [ ${disk%%} -lt 20 ] && echo 成立 || echo 不成立
成立
案例2:判断传入的参数必须为整数
[root@shell day02]# sh age.sh 
请输入你的年龄:1.5
必须为整数
[root@shell day02]# sh age.sh 
请输入你的年龄:abc ^H
必须为整数
[root@shell day02]# sh age.sh 
请输入你的年龄:18
输入的年龄:18
案例3:判断年龄必须为整数并且大于18,小于150岁
[root@shell day02]# cat age.sh 
#!/bin/bash
read -p "请输入你的年龄:" age
expr 0 + $age &>/dev/null
[ $? -ne 0 ] && echo "必须为整数" && exit
[ $age -gt 18 -a $age -lt 150 ] && echo 输入的年龄:$age || echo error
[root@shell day02]# sh age.sh 
请输入你的年龄:18  
error
[root@shell day02]# sh age.sh 
请输入你的年龄:19
输入的年龄:19

[root@shell day02]# sh age.sh 
请输入你的年龄:150  
error
[root@shell day02]# sh age.sh 
请输入你的年龄:149
输入的年龄:149
案例4:判断磁盘使用率如果大于90%则告警发送邮件,小于提示正常
1.配置邮件
yum -y install mailx sendmail
[root@oldboy ~]# vim /etc/mail.rc
set from=alnwei0532@163.com
set smtp=smtp.163.com
set smtp-auth-user=alnwei0532@163.com
set smtp-auth-password=xxxxxx  #授权码DMpkVzzW7wkYsxc4
set smtp-auth=login
测试:echo hehe|mail -s "测试 " 1632183467@qq.com

2.写判断脚本
[root@shell day02]# cat disk.sh 
#!/bin/bash
#将磁盘使用率取出来赋值给disk_use
disk_use=`df -h|awk '/sda3/{print $(NF-1)}'`

#判断比较如果大于9,发送邮件告警

if [ ${disk_use%%} -gt 9 ]
then
    echo 当前磁盘使用率为$disk_use|mail -s "磁盘使用率异常 " 1632183467@qq.com
else
    echo 磁盘使用正常,当前使用率为$disk_use
fi

3.执行测试
[root@shell day02]# sh disk.sh 
磁盘使用正常,当前使用率为10%

作业:巡检脚本
内存使用率告警
负载使用率告警
服务是否在线 80 22
4.文件判断
语法结构:
        语法1: test -f /etc/hosts
        语法2: [ -f /etc/hosts ]
判断符号:
-f  # 普通文件存在为真
-d  # 目录存在为真
-e  # 文件(目录or文件)存在为真
-r  # 文件可读为真
-w  # 文件可写为真
-x  # 文件执行为真
-a  # 并且
-o  # 或者

示例:
[root@shell day02]# [ -f /etc/hosts ] && echo 文件存在 || echo 文件不存在
文件存在
[root@shell day02]# [ -d /etc/hosts ] && echo 文件存在 || echo 文件不存在
文件不存在
[root@shell day02]# [ -d /etc ] && echo 文件存在 || echo 文件不存在
文件存在
[root@shell day02]# [ -e /etc ] && echo 文件存在 || echo 文件不存在
文件存在
[root@shell day02]# [ -e /etc/hosts ] && echo 文件存在 || echo 文件不存在
文件存在
[root@shell day02]# [ -r /etc/hosts ] && echo 文件存在 || echo 文件不存在
文件存在
[root@shell day02]# [ -w /etc/hosts ] && echo 文件存在 || echo 文件不存在
文件存在
[root@shell day02]# [ -x /etc/hosts ] && echo 文件存在 || echo 文件不存在
文件不存在
案例1:判断文件的案例
[root@shell day02]# cat test.sh 
#!/bin/bash
[ -f ./env.txt ] && . ./env.txt
echo $name
echo $age
[root@shell day02]# sh test.sh 
oldboy
123
案例2:判断目录的案例
[root@shell day02]# cat dir.sh 
[ -d /data ] || mkdir /data

[root@shell day02]# sh dir.sh 
[root@shell day02]# ll -d /data/
drwxr-xr-x 2 root root 6  6月  2 20:18 /data/
[root@shell day02]# cat dir.sh 
5.字符串比对
语法结构:
        [ 字符串1 = 字符串2 ]
        [ 字符串1 != 字符串2 ]

比对符号:
=   # 等于
!=  # 不等于
-z  # 长度为0则为真
-n  # 长度不为0为真
-a  
-o

示例:
[root@shell day02]# [ root = root ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [ root = roott ] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [ root != roott ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [ 10 = 10 ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [ 10 = 100 ] && echo 成立 || echo 不成立
不成立

#扩展:字符串比对方式支持正则
$$  #并且
||  #或者
示例:
[root@shell day02]# [[  root =~ ^r  ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[  root =~ t$  ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[  root =~ [abc]  ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[  root =~ [a-z]  ]] && echo 成立 || echo 不成立
成立
案例1:要求前面的字符串必须为连续的字符串
[root@shell day02]# [[  3ro2ot1 =~ ^[a-z]+  ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[  ro2ot1 =~ ^[a-z]+  ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[  ro2ot1 =~ ^[a-z]+$  ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[  ro2ot =~ ^[a-z]+$  ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[  root =~ ^[a-z]+$  ]] && echo 成立 || echo 不成立
成立

#对表达式进行取反 !
[root@shell day02]# [[ ! root =~ ^[a-z]+$  ]] && echo 成立 || echo 不成立
不成立
案例2:要求前面字符串必须是数字整数
[root@shell day02]# [[ 12q =~ [1] ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ 12q =~ [0-9] ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ 12q =~ [0-9]+$ ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 12 =~ [0-9]+$ ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ a12 =~ ^[0-9]+$ ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ 12 =~ ^[0-9]+$ ]] && echo 成立 || echo 不成立
成立
案例3:判断用户输入的姓名必须为字符串
[root@shell day02]# cat age.sh 
#!/bin/bash
read -p "请输入姓名:" name
if [[ $name =~ ^[a-z]+$ ]]
then
    echo $name
else
    echo "请输入正确的姓名"
    exit
fi

read -p "请输入你的年龄:" age
expr 0 + $age &>/dev/null
[ $? -ne 0 ] && echo "必须为整数" && exit
[ $age -gt 18 -a $age -lt 150 ] && echo 输入的年龄: $age || echo error
[root@shell day02]# sh age.sh 
请输入姓名:12
请输入正确的姓名
[root@shell day02]# sh age.sh 
请输入姓名:asdsfdd
asdsfdd
请输入你的年龄:19
输入的年龄: 19
案例扩展
#并且和或者
[root@shell day02]# [[ root =~ ^r && user =~ r$ ]] && echo 成立 || echo 不成立
成立
[root@shell day02]# [[ root =~ ^r && user =~ ^r ]] && echo 成立 || echo 不成立
不成立
[root@shell day02]# [[ root =~ ^r || user =~ ^r ]] && echo 成立 || echo 不成立
成立

-z #长度为0则为真
[root@shell day02]# [ -z "" ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [ -z "aa" ] && echo 成立 || echo 不成立
不成立

-n #长度不为0为真
[root@shell day02]# [ -n "aa" ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [ -n "" ] && echo 成立 || echo 不成立
不成立

[root@shell day02]# [ -z "$user" ] && echo 成立 || echo 不成立
成立
[root@shell day02]# [ -n "$user" ] && echo 成立 || echo 不成立
不成立
6.重点总结
子串知识
    统计长度wc -L awk expr
    统计字符串小于3的输出 for循环 awk行 awk列输出
    删除 #%
    替换

数值运算
expr
$[]
$(())
let i++
bc
awk
加减乘除计算机 三种传承方式

整数比较
-eq
-ne
-gt
-ge
-lt
-le
-a
-o
[ 10 -eq 10 ]
微信、邮件告警
统计磁盘使用率告警
统计内存使用率告警
统计负载使用率告警
统计端口
统计进程
----------------巡检脚本---------
....
主机名
IP地址
内核
操作系统
负载
内存
磁盘
开启了服务
...

文件判断
-f
-d
字符串比对
[ root = root ]
[ root != rot ]
-z #长度为0为真
-n #长度不为0为真
-a 
-o

字符串正则
[[ root =~ ^r ]]
&& 并且
|| 或者

传入参数必须为整数 年龄、计算器、不能为空,可以用正则也可以用expr
传入参数必须为字符串

四、shell语句-day056

1.if判断
语法结构:
#一个条件一个结果,表达式成立则执行,不成立什么操作都没有
if [条件表达式];then 数值比对、字符串比对、文件判断、正则比对..
    执行的命令集合
fi

#一个条件两个结果   [ 10 -eq 10 ] && echo 成立 || echo 不成立
if [ 条件表达式 ]
then
    命令集合
else
    命令集合
fi

#多个条件多个结果
if [ 条件表达式 ]
then
    命令集合
elif [ 条件表达式 ]
then
    命令集合
elif [ 条件表达式 ]
then
    命令集合
else 
    命令集合
fi
案例1:传入两个参数、进行比大小
需求:sh test.sh 10 20
10<10
`v1.0`
[root@shell day03]# cat test.sh 
#!/bin/bash
if [ $1 -eq $2 ];then
    echo "$1=$2"
elif [ $1 -gt $2 ];then
    echo "$1>$2"
else
    echo "$1<$2"
fi

[root@shell day03]# sh test.sh 10 12
10<12
[root@shell day03]# sh test.sh 10 10
10=10
[root@shell day03]# sh test.sh 10 3
10>3

`v2.0判断传入的参数是否合法`
[root@shell day03]# cat test.sh 
#!/bin/bash
if [[ $# =~ 2 && $1 =~ ^[0-9]+$ && $2 =~ ^[0-9]+$ ]];then
   if [ $1 -eq $2 ];then
    echo "$1=$2"
   elif [ $1 -gt $2 ];then
    echo "$1>$2"
   else
    echo "$1<$2"
   fi
else
    echo "必须为两个参数"
    exit
fi
[root@shell day03]# sh test.sh 
必须为两个参数
[root@shell day03]# sh test.sh 1
必须为两个参数
[root@shell day03]# sh test.sh 1 2
1<2
[root@shell day03]# sh test.sh 1 1
1=1
[root@shell day03]# sh test.sh 1 0
1>0
[root@shell day03]# sh test.sh a a
必须为两个参数
案例2:判断网络是否正常
`写死参数`
ping -c1 -W1 www.baidu.com &>/dev/null
if [ $? -eq 0 ];then
    echo "网络是通的"
else
    echo "网络不通"
fi
[root@shell day03]# sh ping.sh 
网络是通的

`直接传参`
[root@shell day03]# cat ping.sh 
#!/bin/bash
ping -c1 -W1 $1 &>/dev/null
if [ $? -eq 0 ];then
    echo "$1网络是通的"
else
    echo "$1网络不通"
fi
[root@shell day03]# sh ping.sh www.sina.com
www.sina.com网络是通的
[root@shell day03]# sh ping.sh www.sinaaaa.com
www.sinaaaa.com网络是通的
[root@shell day03]# sh ping.sh www.sinaaaaaaaaa.com
www.sinaaaaaaaaa.com网络不通

`赋值传参`
[root@shell day03]# cat ping.sh 
#!/bin/bash
url=$1
ping -c1 -W1 $url &>/dev/null
if [ $? -eq 0 ];then
    echo "$url网络是通的"
else
    echo "$url网络不通"
fi
[root@shell day03]# sh ping.sh www.weibo.com
www.weibo.com网络是通的
[root@shell day03]# sh ping.sh www.weiboddd.com
www.weiboddd.com网络不通
2.while循环
01.语法结构:
while [ 条件表达式 ] # 必须成立才执行
do
    命令集合
done

`示例:死循环脚本`
#整数比对为真
[root@shell day03]# cat while.sh 
#!/bin/bash
while [ 10 -eq 10 ]
do
    echo hehe
    sleep 1
done
[root@shell day03]# sh while.sh 
hehe
hehe

#文件比对为真
[root@shell day03]# cat while.sh 
#!/bin/bash
while [ -f /etc/hosts ]

do
    echo hehe
    sleep 1
done
[root@shell day03]# sh while.sh 
hehe
hehe
hehe

#true为真
[root@shell day03]# cat while.sh 
#!/bin/bash
while true

do
    echo hehe
    sleep 1
done
[root@shell day03]# sh while.sh
hehe
hehe
hehe
案例1:在循环里面用exit
[root@shell day03]# cat while.sh 
#!/bin/bash
while true

do
    echo hehe
    sleep 1
    exit
    echo oldboy ...
done
echo done .........
[root@shell day03]# sh while.sh
hehe
案例2:在循环里用break
`跳出一层循环`
[root@shell day03]# cat while.sh 
#!/bin/bash
while true

do
    echo hehe
    sleep 1
    break
    echo oldboy ...
done
echo done .........
[root@shell day03]# sh while.sh 
hehe
done .........

`跳出2层循环`
[root@shell day03]# cat while.sh 
#!/bin/bash
while true
do
   while true

   do
    echo hehe
    sleep 1
    break 2
    echo oldboy ...
   done
echo done .........
done
echo a........
[root@shell day03]# sh while.sh 
hehe
a........
案例3:continue
while true
do
   while true

   do
    echo hehe
    sleep 1
    continue
    echo oldboy ...
   done
echo done .........
done
echo a........
[root@shell day03]# sh while.sh 
hehe
hehe
hehe
案例4:除了用exit break continue控制流程,还可以使用read控制流程
[root@shell day03]# cat while.sh 
#!/bin/bash
while true
do
    read -p "请输入姓名;" name
    echo $name
    continue
done
[root@shell day03]# sh while.sh 
请输入姓名;name
name
请输入姓名;zhang
zhang
3.综合案例
案例1:一级菜单
`安装软件 nginx php redis`
[root@shell day03]# cat menu.sh 
#!/bin/bash
#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Color

echo -e "${BLUE}"
echo -e "ttttt1.NGINX"
echo -e "ttttt2.PHP"
echo -e "ttttt3.REDIS"
echo -e "${NC}"

read -p "请输入安装软件的编号:" num
if [ $num -eq 1 ];then
    echo "yum -y install nginx......."
elif [ $num -eq 2 ];then
    echo "yum -y install php......"
elif [ $num -eq 3 ];then
    echo "yum -y install redis....."
fi
[root@shell day03]# sh menu.sh 

                    1.NGINX
                    2.PHP
                    3.REDIS

请输入安装软件的编号:1
yum -y install nginx.......
案例2:一级菜单查看操作系统信息
[root@shell day03]# cat os.sh 
#!/bin/bash
#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Colo
#提示菜单
echo -e "${BLUE}"
echo -e "ttttt1.查看内存"
echo -e "ttttt2.查看负载"
echo -e "ttttt3.查看磁盘"
echo -e "${NC}"

read -p "请输入查看系统信息编号;" num
if [ $num -eq 1 ];then
    free -h
elif [ $num -eq 2 ];then
    uptime
elif [ $num -eq 3 ];then
    df -h
fi

[root@shell day03]# sh os.sh 

                    1.查看内存
                    2.查看负载
                    3.查看磁盘

请输入查看系统信息编号;1
              total        used        free      shared  buff/cache   available
Mem:          444Mi       157Mi        82Mi        10Mi       204Mi       264Mi
Swap:         2.0Gi        48Mi       2.0Gi
案例3:基于案例2执行命令后不让脚本退出继续在里面
[root@shell day03]# cat os.sh 
#!/bin/bash
#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Colo
#提示菜单
echo -e "${BLUE}"
echo -e "ttttt1.查看内存"
echo -e "ttttt2.查看负载"
echo -e "ttttt3.查看磁盘"
echo -e "ttttt4.退出"
echo -e "${NC}"

while true
do
   read -p "请输入查看系统信息编号;" num
   [ -z $num ] && echo "必须输入个编号" && continue
   if [ $num = 1 -o $num = 2 -o $num = 3 -o $num = 4 ];then
    if [ $num -eq 1 ];then
        free -h
    elif [ $num -eq 2 ];then
        uptime
    elif [ $num -eq 3 ];then
        df -h
    elif [ $num -eq 4 ];then
        exit
    fi
   else
      echo "请输入1|2|3"
      continue      
   fi
done

[root@shell day03]# sh os.sh 

                    1.查看内存
                    2.查看负载
                    3.查看磁盘
                    4.退出

请输入查看系统信息编号;   
必须输入个编号
请输入查看系统信息编号;1
              total        used        free      shared  buff/cache   available
Mem:          444Mi       157Mi        82Mi        10Mi       204Mi       264Mi
Swap:         2.0Gi        48Mi       2.0Gi
案例4:二级菜单
[root@shell day03]# cat menu.sh 
#!/bin/bash
#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Color

echo -e "${BLUE}"
echo -e "ttttt1.NGINX"
echo -e "ttttt2.PHP"
echo -e "ttttt3.REDIS"
echo -e "${NC}"

read -p "请输入安装软件的编号:" num
if [ $num -eq 1 ];then
    echo -e "${BLUE}"
    echo -e "ttttt1.NGINX1.6"
    echo -e "ttttt2.nginx1.7"
    echo -e "ttttt3.nginx1.8"
    echo -e "${NC}"
    read -p "输入安装的版本编号:" num1
    if [ $num1 -eq 1 ];then
        echo "安装nginx1.6....."
    elif [ $num1 -eq 2 ];then
        echo "安装nginx1.8"
    fi
elif [ $num -eq 2 ];then
    echo -e "${BLUE}"
        echo -e "ttttt1.php5.6"
        echo -e "ttttt2.php5.7"
        echo -e "ttttt3.php5.8"
        echo -e "${NC}"
        read -p "输入安装的版本编号:" num1
        if [ $num1 -eq 1 ];then
            echo "安装php5.6....."
        elif [ $num1 -eq 2 ];then
                echo "安装php5.8"
        fi
fi

[root@shell day03]# sh menu.sh 

                    1.NGINX
                    2.PHP
                    3.REDIS

请输入安装软件的编号:1

                    1.NGINX1.6
                    2.nginx1.7
                    3.nginx1.8

输入安装的版本编号:1
安装nginx1.6.....
案例5.使用while循环控制一级和二级菜单
[root@shell day03]# cat menu.sh 
#!/bin/bash
#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Color

#一级菜单
men1(){
echo -e "${BLUE}"
echo -e "ttttt1.NGINX"
echo -e "ttttt2.PHP"
echo -e "ttttt3.REDIS"
echo -e "${NC}"
}
#二级菜单
men2(){
echo -e "${BLUE}"
echo -e "ttttt1.NGINX1.6"
echo -e "ttttt2.nginx1.7"
echo -e "ttttt3.菜单"
echo -e "ttttt4.退出"
echo -e "${NC}"
}

while true
do
men1
read -p "请输入安装软件的编号:" num
if [ $num -eq 1 ];then
    men2
    while true
    do  
    read -p "输入安装的版本编号[h|3菜单]:" num1
    if [ $num1 = 1 ];then
        echo "安装nginx1.6....."
    elif [ $num1 = 2 ];then
        echo "安装nginx1.8"
    elif [ $num1 = 3 -o $num1 = h ];then
        men2
    elif [ $num1 = 4 ];then
        break
    fi
    done
fi
done

[root@shell day03]# sh menu.sh 

                    1.NGINX
                    2.PHP
                    3.REDIS

请输入安装软件的编号:1

                    1.NGINX1.6
                    2.nginx1.7
                    3.菜单
                    4.退出

输入安装的版本编号[h|3菜单]:3

                    1.NGINX1.6
                    2.nginx1.7
                    3.菜单
                    4.退出
案例6:猜数字1-100
先随机生成一个中奖号码
提示让用户猜1-100之间的数字,输入大的提示大了,小了提示小了,正确提示中奖了并退出脚本
`生成随机数`
echo $((RANDOM))# RANDOM 0-32767之间随机数
echo $((RANDOM%100+1))  #1-100的随机数

[root@shell day03]# cat ran.sh 
#生成1-100随机数
ran=`echo $((RANDOM%100+1))`

#循环判断
while true
do
    let i++
    read -p "请输入1-100之间的数字:" num
    if [ $num -gt $ran ];then
        echo "你猜大了"
    elif [ $num -lt $ran ];then
        echo "你猜小了"
    else
        break
    fi
done
echo "总共猜了 $i 次"
echo "恭喜你中奖了金额999999999美金"

[root@shell day03]# sh ran.sh 
请输入1-100之间的数字:1
你猜小了
请输入1-100之间的数字:50
你猜大了
请输入1-100之间的数字:34
你猜小了
请输入1-100之间的数字:45
你猜小了
请输入1-100之间的数字:48
你猜大了
请输入1-100之间的数字:46
总共猜了 6 次
恭喜你中奖了金额999999999美金
4.case语句
语法结构
case $1 in
        匹配序列1)
           命令集合
        ;;
        匹配序列2)
           命令集合
        ;;
        匹配序列3)
           命令集合
        ;;
        *)
        提示
esac

`示例`
[root@shell day03]# cat case.sh 
case $1 in
    linux)
        echo linux....
    ;;
    shell)
        echo shell.....
    ;;
    mysql)
        echo mysql....
    ;;
    *)
        echo "Usage:$0 [linux|shell|mysql]"
esac
[root@shell day03]# sh case.sh ll
Usage:case.sh [linux|shell|mysql]
[root@shell day03]# sh case.sh linux
linux....
案例1:使用case查看系统信息
[root@shell day03]# cat case.sh 
#!/bin/bash
#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Colo

men(){
echo -e "${BLUE}"
echo -e "ttttt1|f.查看内存"
echo -e "ttttt2|u.查看负载"
echo -e "ttttt3|d.查看磁盘"
echo -e "ttttt4|q.退出"
echo -e "ttttt5|h.菜单"
echo -e "${NC}"
}

men
while true
do
read -p "请输入要查看信息的编号[h菜单]:" num

case $num in
    1|f)
        free -h
    ;;
    2|u)
        uptime
    ;;
    3|d)
        df -h
    ;;
    4|q)
        exit
    ;;
    5|h)
        men
    ;;
    *)
        echo "Usage:$0 1|2|3|4"
esac
done

[root@shell day03]# sh case.sh 

                    1|f.查看内存
                    2|u.查看负载
                    3|d.查看磁盘
                    4|q.退出
                    5|h.菜单

请输入要查看信息的编号[h菜单]:5

                    1|f.查看内存
                    2|u.查看负载
                    3|d.查看磁盘
                    4|q.退出
                    5|h.菜单
案例2:nginx的启动脚本
nginx启动方式有两种,一种是是使用systemctl方式管理,一种是直接使用命令运行。
systemctl start nginx
systemctl stop nginx
命令:
/usr/sbin/nginx  # 启动
/usr/sbin/nginx -s stop #停止
/usr/sbin/nginx -s reload # 重新加载
/usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx  # 表示重启

`v1.0`
[root@shell day03]# cat nginx.sh 
#!/bin/bash
case $1 in
    start)
        /usr/sbin/nginx
    ;;
    stop)
        /usr/sbin/nginx -s stop
    ;;
    reload)
        /usr/sbin/nginx -s reload
    ;;
    restart)
        /usr/sbin/nginx -s stop && sleep 1 && /usr/sbin/nginx
    ;;
    status)
        if [ `netstat -tnulp|grep nginx|wc -l` -gt 0 ];then
            echo "nginx运行汇总,监听在以下端口"
            netstat -tnulp|grep nginx|awk '{print $4}'
        else
            echo "Nginx 未运行"
        fi
    ;;
    *)
        echo "Usage $0 [start|stop|restart|reload|status]"
esac
[root@shell day03]# sh nginx.sh start
[root@shell day03]# sh nginx.sh status
nginx运行汇总,监听在以下端口
0.0.0.0:80

`v2.0判断每个命令的结果`
[root@shell day03]# cat nginx.sh 
#!/bin/bash
ngx=/usr/sbin/nginx
case $1 in
    start)
        $ngx
        if [ $? -eq 0 ];then
            echo "nginx $1 成功"
        else
            echo "nginx $1 成功"
        fi
    ;;
    stop)
        $ngx -s stop
        if [ $? -eq 0 ];then
                        echo "nginx $1 成功"
                else
                        echo "nginx $1 成功"
                fi
    ;;
    reload)
        $ngx -s reload
        if [ $? -eq 0 ];then
                        echo "nginx $1 成功"
                else
                        echo "nginx $1 成功"
                fi
    ;;
    restart)
        $ngx -s stop && sleep 1 && $ngx
        if [ $? -eq 0 ];then
                        echo "nginx $1 成功"
                else
                        echo "nginx $1 成功"
                fi
    ;;
    status)
        if [ `netstat -tnulp|grep nginx|wc -l` -gt 0 ];then
            echo "nginx运行汇总,监听在以下端口"
            netstat -tnulp|grep nginx|awk '{print $4}'
        else
            echo "Nginx 未运行"
        fi
    ;;
    *)
        echo "Usage $0 [start|stop|restart|reload|status]"
esac
[root@shell day03]# sh nginx.sh 
Usage nginx.sh [start|stop|restart|reload|status]
[root@shell day03]# sh nginx.sh start
nginx start 成功

`v3.0`
[root@shell day03]# cat nginx.sh 
#!/bin/bash
ngx=/usr/sbin/nginx

ac=$1
Te(){
     if [ $? -eq 0 ];then
             echo "nginx $1 成功"
         else
             echo "nginx $1 成功"
         fi
}

case $1 in
    start)
        $ngx
        Te
    ;;
    stop)
        $ngx -s stop
        Te
    ;;
    reload)
        $ngx -s reload
        Te
    ;;
    restart)
        $ngx -s stop && sleep 1 && $ngx
        Te
    ;;
    status)
        if [ `netstat -tnulp|grep nginx|wc -l` -gt 0 ];then
            echo "nginx运行汇总,监听在以下端口"
            netstat -tnulp|grep nginx|awk '{print $4}'
        else
            echo "Nginx 未运行"
        fi
    ;;
    *)
        echo "Usage $0 [start|stop|restart|reload|status]"
esac
[root@shell day03]# sh nginx.sh 
Usage nginx.sh [start|stop|restart|reload|status]
[root@shell day03]# sh nginx.sh status
nginx运行汇总,监听在以下端口
0.0.0.0:80
案例3:调用系统的函数库
[root@shell day03]# cat ping.sh 
#!/bin/bash

[ -f /etc/init.d/functions ] && . /etc/init.d/functions
url=$1
ping -c1 -W1 $url &>/dev/null
if [ $? -eq 0 ];then
    action "$url网络是通的" /bin/true 
else
    action "$url网络不通" /bin/false
fi
[root@shell day03]# sh ping.sh 
网络不通 [FAILED]
[root@shell day03]# sh ping.sh wwww.baidu.com
wwww.baidu.com网络是通的 [  OK  ]

`扩展`计算1 100总和
[root@shell day03]# echo {1..100} |sed 's# #+#g'|bc
5050
[root@shell day03]# seq -s + 100|bc
5050
作业1:抓阄 前5名谁的数字大优先大宝剑
1.输入姓名
2.屏幕上输出姓名和1-100产生的1个随机数
3.不能退出、继续输入姓名
4.出现过的数字不能在输出了
5.所有姓名输入完成后退出脚本 对输入过的进行逆序排序
sh test.sh
张三 66
李四 89
老王 55
老李 99

`参考`
[root@shell day04]# cat zj.sh 
#!/bin/bash
>ran.txt
while true
do
    read -p "请输入姓名[输入ok结束]:" name
    [ `cat ran.txt|wc -l` -eq 100 ] && "抓完了没号了" && exit
    while true
    do
        ran=`echo $((RANDOM%100+1))`
        if [ `cat ran.txt|grep -w $ran|wc -l` -eq 1 ];then
            continue
        else
            break
        fi
    done
    [ $name = ok ] && break
    echo -e "$namet$ran"|tee -a ran.txt
done
echo "抓阄完毕,排行如下"
sort -rnk2 ran.txt|head -5
作业2:反向破解随机数 0-32767
[root@shell ~]# echo $((RANDOM))
10629
取md5 8位
[root@shell day03]# echo $((RANDOM))|md5sum|cut -c1-8
ac180b7c

ad518894  对应着是0-3
c0358b44
2b492a4b
d668f8f
f9b3135

`参考`
[root@shell day04]# cat pj.sh 
#!/bin/bash
for i in {0..32767}
do
        md=`echo $i|md5sum|cut -c1-8`
    if [[ $md =~ ad518894 || $md =~ c0358b44 || $md =~ 2b492a4b || $md =~ d668f8f || $md =~ f9b3135 ]];then
        echo -e "$it $md"

    fi 
done
案例:跳板机案例v1.0-day-057
需求:
1.通过web01跳板登录到后端服务器上
2.web01跳板机需要和后端所有的服务器做免秘钥
[root@shell day04]# cat jumpserver.sh 
#!/bin/bash
WEB02=172.16.1.8
NFS=172.16.1.31
BACKUP=172.16.1.41
MySQL=172.16.1.51

#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Color

echo -e "${BLUE}"
echo -e "ttttt1.$WEB02"
echo -e "ttttt2.$NFS"
echo -e "ttttt3.$BACKUP"
echo -e "ttttt4.$MySQL"
echo -e "${NC}"

while true
do
    read -p "输入要登录服务器的编号:" num
    case $num in
        1)
            ssh $WEB02
            ;;
        2)
            ssh $NFS
            ;;
        4)
            ssh $MySQL
            ;;
        *)
            continue
    esac
done
案例:跳板机v2.0
需求:
1.角色 运维 开发 测试
2.用户密码登录
[root@shell day04]# cat jumpserver.sh 
#!/bin/bash
WEB02=172.16.1.8
NFS=172.16.1.31
BACKUP=172.16.1.41
MySQL=172.16.1.51

#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Color

#角色定义
#一级菜单运维/开发
ro(){
    echo -e "${BLUE}"
    echo -e "ttttt1.运维"
    echo -e "ttttt2.开发"
    echo -e "${NC}"
}
#二级菜单运维可连接服务
ops(){
    echo -e "${BLUE}"
    echo -e "ttttt1.$WEB02"
    echo -e "ttttt2.$NFS"
    echo -e "ttttt3.$BACKUP"
    echo -e "ttttt4.$MySQL"
    echo -e "ttttt5.菜单"
    echo -e "${NC}"
}

#二级菜单开发可连接服务
dev(){
    echo -e "${BLUE}"
    echo -e "ttttt1.$MySQL"
    echo -e "${NC}"
}

while true
do
    ro
    read -p "请输入角色编号:" num
#==========================判断密码
    while true
    do
        read -p "请输入运维密码:" pass
        let i++
        if [ $i -eq 3 ];then
            read -p "输入错误次数过多,输入邮箱找回密码:" mail
            ran=`echo $((RANDOM))`
            echo $ran|mail -s "跳板机验证码" "1632183467@qq.com"
            read -p "请输入验证码:" ra
            [ $ran = $ra ] && echo 123 | mail -s "密码" "1632183467@qq.com"
            wait
            unset i
            continue
        fi
        if [ $pass -eq 123 ];then
            break
        elif [ $pass -ne 123 ];then
            echo "输入密码错误、请重新输入密码"
            continue
        fi
    done
#==========================角色判断
    if [ $num -eq 1 ];then
        ops
        while true
        do
            read -p "输入要登录服务器的编号[5|h菜单:]" num
            case $num in
                1)
                    ssh $WEB02
                    ;;
                2)
                    ssh $NFS
                    ;;
                4)
                    ssh $MySQL
                    ;;
                5)
                    ops
                    ;;
                6)
                    break
                    ;;
                *)
                    continue
            esac
        done
    elif [ $num -eq 2 ];then
        dev
        while true
        do
            read -p "输入要登录服务器的编号:" num
            case $num in 
                1)
                    ssh $MySQL
                    ;;
                *)
                    continue
            esac
        done

    fi
done
案例3:跳板机v3.0
#禁止使用ctrl+c ctrl+d 结束信号
#写入profile预留后门
[root@shell day04]# cat jumpserver.sh 
#!/bin/bash
WEB02=172.16.1.8
NFS=172.16.1.31
BACKUP=172.16.1.41
MySQL=172.16.1.51

#颜色定义
RED='33[0;31m'
GREEN='33[0;32m'
YELLOW='33[1;33m'
BLUE='33[0;34m'
NC='33[0m' # No Color

#角色定义
#一级菜单运维/开发
ro(){
    echo -e "${BLUE}"
    echo -e "ttttt1.运维"
    echo -e "ttttt2.开发"
    echo -e "${NC}"
}
#二级菜单运维可连接服务
ops(){
    echo -e "${BLUE}"
    echo -e "ttttt1.$WEB02"
    echo -e "ttttt2.$NFS"
    echo -e "ttttt3.$BACKUP"
    echo -e "ttttt4.$MySQL"
    echo -e "ttttt5.菜单"
    echo -e "${NC}"
}

#二级菜单开发可连接服务
dev(){
    echo -e "${BLUE}"
    echo -e "ttttt1.$MySQL"
    echo -e "${NC}"
}
#禁止使用ctrl+c ctrl+d结束信号
trap "" INT TSTP HUP
#具体实现
while true
do
    ro
    read -p "请输入角色编号:" num
#==========================判断密码
    while true
    do
        read -p "请输入运维密码:" pass
        let i++
        if [ $i -eq 3 ];then
            read -p "输入错误次数过多,输入邮箱找回密码:" mail
            ran=`echo $((RANDOM))`
            echo $ran|mail -s "跳板机验证码" "1632183467@qq.com"
            read -p "请输入验证码:" ra
            [ $ran = $ra ] && echo 123 | mail -s "密码" "1632183467@qq.com"
            wait
            unset i
            continue
        fi
        if [ $pass -eq 123 ];then
            break
        elif [ $pass -ne 123 ];then
            echo "输入密码错误、请重新输入密码"
            continue
        fi
    done
#==========================角色判断
    if [ $num -eq 1 ];then
        ops
        while true
        do
            read -p "输入要登录服务器的编号[5|h菜单:]" num
            case $num in
                1)
                    ssh $WEB02
                    ;;
                2)
                    ssh $NFS
                    ;;
                4)
                    ssh $MySQL
                    ;;
                5)
                    ops
                    ;;
                hm)     # 写入profile后预留后门
                    exit
                    ;;
                6)
                    break
                    ;;
                *)
                    continue
            esac
        done
    elif [ $num -eq 2 ];then
        dev
        while true
        do
            read -p "输入要登录服务器的编号:" num
            case $num in 
                1)
                    ssh $MySQL
                    ;;
                *)
                    continue
            esac
        done

    fi
done
5.for循环
语法结构:
for i in 取值列表   # 数字 字符串 序列 命令 拼接
do
    执行命令集合
done
案例1:循环字符串
[root@shell day04]# cat for.sh
#!/bin/bash
for i in a b c
do
    echo $i
done
[root@shell day04]# sh for.sh 
a
b
c
案例2:循环数字
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in 1 2 3
do
    echo $i
done
[root@shell day04]# sh for.sh 
1
2
3
案例3:循环序列
`数字`
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in {1..5}
do
    echo $i
done
[root@shell day04]# sh for.sh 
1
2
3
4
5

`字符`
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in {a..e}
do
    echo $i
done
[root@shell day04]# sh for.sh 
a
b
c
d
e
案例4:支持循环命令、命令需要加反引号
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in `seq 5`
do
    echo $i
done
[root@shell day04]# sh for.sh 
1
2
3
4
5
案例5.支持输出和值无关的但是和次数有关
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in 1 2 3
do
    echo hehe
done
[root@shell day04]# sh for.sh 
hehe
hehe
hehe
案例6.循环次数
`直接循环`
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in 1 2 3
do
    let a++
done
echo 循环了 $a 次
[root@shell day04]# sh for.sh 
循环了 3 次

`遍历文件`
[root@shell day04]# cat a.txt 
a b c d e
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in `cat a.txt`
do
    let a++
done
echo 循环了 $a 次
[root@shell day04]# sh for.sh 
循环了 5 次

[root@shell day04]# cat a.txt 
aaaaa
bbbbb
ccccc
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in `cat a.txt`
do
    let a++
done
echo 循环了 $a 次
[root@shell day04]# sh for.sh 
循环了 3 次
案例7:拼接
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in 1 2 3
do
    echo oldboy$i
done
[root@shell day04]# sh for.sh 
oldboy1
oldboy2
oldboy3
案例8:批量创建用户脚本
`v1.0`
[root@shell day04]# cat for.sh 
#!/bin/bash
for i in 1 2 3
do
    useradd oldboy$i
done
[root@shell day04]# sh for.sh 
[root@shell day04]# grep oldboy /etc/passwd
oldboy1:x:1000:1000::/home/oldboy1:/bin/bash
oldboy2:x:1001:1001::/home/oldboy2:/bin/bash
oldboy3:x:1002:1002::/home/oldboy3:/bin/bash

`V2.0`
1)批量创建
2)批量删除
3)给用户设置随机密码保留到user.txt

第一步:用户拼接
[root@shell day04]# cat user.sh 
#!/bin/bash
read -p "输入用户的前缀:" prefix
read -p "输入用户个数:" num

for i in `seq $num`
do
    echo $prefix$i
done

第二步:判断删除还是创建
[root@shell day04]# cat user.sh 
#!/bin/bash
read -p "输入用户的前缀:" prefix
read -p "输入用户个数:" num

for i in `seq $num`
do
    echo $prefix$i
done

read -p "创建[y]或者删除[d]以上用户:" a

for c in `seq $num`
do
    case $a in
        y)
            user=$prefix$c
            useradd $user
            ;;
        d)
            user=$prefix$c
            userdel -r $user
            ;;
    esac
done

`v3.0`
[root@shell day04]# cat user.sh 
#!/bin/bash
read -p "输入用户的前缀:" prefix
read -p "输入用户个数:" num

for i in `seq $num`
do
    echo $prefix$i
done

read -p "创建[y]或者删除[d]以上用户:" a

for c in `seq $num`
do
    case $a in
        y)
            user=$prefix$c
            id $user &>/dev/null
            if [ $? -ne 0 ];then
                useradd $user
                [ $? -eq 0 ] && echo $user 创建成功
            else
                echo "$user 已存在"
            fi
            ;;
        d)
            user=$prefix$c
            id $user &>/dev/null
            if [ $? -eq 0 ];then
                userdel -r $user
                [ $? -eq 0 ] && echo $user 删除成功
            else
                echo "$user 不存在"

            fi
            ;;
    esac
done
案例9:判断一组IP是否在线,通在线10.0.0.1-10.0.0.254
`框架`
[root@shell day04]# cat ping.sh 
#!/bin/bash
for i in `seq 254`
do
    echo 10.0.0.$i
done

`笔试题`
[root@shell day04]# cat ping.sh 
#!/bin/bash
for i in `seq 254`
do
    {
    ip=10.0.0.$i
    ping -c1 -W1 $ip &>/dev/null
    [ $? -eq 0 ] && echo $ip "在线....."
    } &     #开启多线程执行
done
wait        #等待上一个后台任务结束后再执行后面的
echo "验证完成"

[root@shell day04]# sh ping.sh 
10.0.0.1 在线.....
10.0.0.8 在线.....
10.0.0.2 在线.....
10.0.0.51 在线.....
10.0.0.7 在线.....
验证完成
案例10:从1加到100
[root@shell day04]# cat ran.sh 
#!/bin/bash
for i in `seq 100`
do
    co=$[$co+$i]
done
echo  等于 $co
[root@shell day04]# sh ran.sh 
等于 5050
-------
#执行过程
#!/bin/bash
for i in `seq 100`
do
     co=$[$co+$i]
     i=1
     co=$[0+1]
     co=1
     i=2
     co=$[1+2]
     co=3

done
echo 等于 $co
案例11:将1-100之间能整除3的进行相加
[root@shell day04]# cat test.sh 
#!/bin/bash
>1.txt
for i in {1..100}
do
    num=$i
    if [ `echo $i % 3|bc` -eq 0 ];then
        echo $i >> 1.txt
    fi
done
sum=`cat 1.txt|xargs -n100|sed 's# #+#g'|bc`
echo "和是$sum"
[root@shell day04]# sh test.sh 
和是1683
案例12:支持创建在文件中的用户
[root@shell day04]# cat u.sh 
#!/bin/bash
for i in `cat name.txt`
do
    useradd $i
done

[root@shell day04]# sh u.sh 
[root@shell day04]# tail -3 /etc/passwd
zhangsan:x:1010:1010::/home/zhangsan:/bin/bash
lisi:x:1011:1011::/home/lisi:/bin/bash
laowang:x:1012:1012::/home/laowang:/bin/bash

#随机密码的命令
[root@shell day04]# date +%N|md5sum|cut -c1-8
9a90d2a4

[root@shell day04]# echo $((RANDOM))|md5sum|cut -c1-8
2f791430

yum -y install expect
[root@shell day04]# mkpasswd
dz?U4cH5u
day057总结
#case跳板机 for循环 批量创建用户 ping
其他生活中的案例:
1.中午吃啥、使用脚本随机选择一个
2.双色球 从1-33数字里随机6个红球  在从1-16里面随机一个篮球,注数
3.去老男孩大饭店吃饭 会员 办卡 充钱
点餐
1.xx 200元
2.xxx 500元
结账
6.while循环:扩展-day058
语法结构
while [ 条件表达式 ] 为真则执行,假不执行
do
    命令集合
done
案例1:while死循环,笔试题或者面试题
shell怎么写一个死循环while true
while true
do
    echo aa
done
案例2:while从1加到100
[root@shell day05]# cat while.sh 
#!/bin/bash
i=1
while [ $i -le 100 ]
do
    count=$[count+i]
    let i++
done
echo $count
[root@shell day05]# sh while.sh 
5050
案例3:while按行读取文件
[root@shell day05]# cat read.sh 
#!/bin/bash
while read line
do
    echo $line
done</etc/hosts     #读取/etc/hosts

[root@shell day05]# sh read.sh 
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
127.0.0.1 www.test.com
--------
[root@shell day05]# sh read.sh 
3
[root@shell day05]# cat read.sh 
#!/bin/bash
while read line
do
    let i++
done</etc/hosts
echo $i
[root@shell day05]# sh read.sh 
3
--------
[root@shell day05]# cat read.sh 
#!/bin/bash
while read line
do
    let i++
done</etc/passwd
echo $i
[root@shell day05]# sh read.sh 
40
案例4:创建文件中用户和对应的密码
[root@shell day05]# cat u.txt 
zs ef123.com
li cd123.com
lw ab123.com

[root@shell day05]# cat for.sh 
#!/bin/bash
while read line
do
    user=`echo $line|awk '{print $1}'`
    pass=`echo $line|awk '{print $2}'`
    useradd $user
    echo $pass|passwd --stdin $user
done<u.txt

[root@shell day05]# tail -3 /etc/passwd
zs:x:1019:1019::/home/zs:/bin/bash
li:x:1020:1020::/home/li:/bin/bash
lw:x:1021:1021::/home/lw:/bin/bash

#命令行的for循环
[root@shell day05]# for i in 1 2 3;do echo $i ;done
1
2
3

for循环解决案例
#月浩班长的for循环奇偶数
[root@web01 ~]# cat a.sh 
username=""
line_num=1

for i in $(cat u.txt)
do 
  if [ $((line_num % 2)) -eq 1 ];then
    useradd $i
    username=$i
  else
    echo $i|passwd --stdin $username
  fi  
    ((line_num++))
done
7.函数

1.完成特定功能的代码块
2.函数类似变量、可以重复复用
3.函数只定义,不调用不会执行,变量定义就会执行

01.函数的定义
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    echo "第一种定义方式"
}

function fun2(){
    echo "第二种定义方式"
}

function fun3 {
    echo "第三种定义方式"
}
fun1
fun2
fun3
[root@shell day05]# sh fun.sh 
第一种定义方式
第二种定义方式
第三种定义方式
02.函数的传参
#函数中的$1 是函数名称后面的第一个参数,而不是脚本的第一个参数
`示例1`
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $1 ];then
        echo "$1 文件存在"
    else
        echo "$1 文件不存在"
    fi
}
fun1 /etc/hosts
[root@shell day05]# sh fun.sh 
/etc/hosts 文件存在

`示例2`
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $2 ];then
        echo "$2 文件存在"
    else
        echo "$2 文件不存在"
    fi
}
fun1 /etc/hosts /etc/passwd
[root@shell day05]# sh fun.sh 
/etc/passwd 文件存在

`示例3`
#函数名称后面的$1脚本的第一个参数,也是函数中的第一个参数
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $1 ];then
        echo "$1 文件存在"
    else
        echo "$1 文件不存在"
    fi
}
fun1 $1
[root@shell day05]# sh fun.sh /etc/hosts
/etc/hosts 文件存在
[root@shell day05]# sh fun.sh /etc/hostssssss
/etc/hostssssss 文件不存在

`示例4`
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $1 ];then
        echo "$1 文件存在"
    else
        echo "$1 文件不存在"
    fi
}
fun1 $2 $1
[root@shell day05]# sh fun.sh /etc/hosts /etc/passwd
/etc/passwd 文件存在

`示例5`
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $2 ];then
        echo "$2 文件存在"
    else
        echo "$2 文件不存在"
    fi
}
fun1 $2 $1
[root@shell day05]# sh fun.sh /etc/passwd /etc/hosts
/etc/passwd 文件存在

`示例6`
#除了函数的传参我们还可以使用赋值传参,因为函数中支持直接调用变量
[root@shell day05]# cat fun.sh 
#!/bin/bash
file=$1
fun1(){
    if [ -f $file ];then
        echo "$file 文件存在"
    else
        echo "$file 文件不存在"
    fi
}
fun1 
[root@shell day05]# sh fun.sh /etc/hosts
/etc/hosts 文件存在
[root@shell day05]# sh fun.sh /etc/hostssss
/etc/hostssss 文件不存在
03.函数的变量
`示例1`
[root@shell day05]# cat fun.sh 
#!/bin/bash
name=oldboy
fun1(){
    echo $name
}
fun1 
[root@shell day05]# sh fun.sh 
oldboy

`示例2`
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    local name=oldoby       #指定只在函数体中生效
    echo $name
}
fun1 
[root@shell day05]# sh fun.sh 
oldoby

`示例3`
[root@shell day05]# cat fun.sh 
#!/bin/bash
name=oldgirl
fun1(){
    local name=oldoby       #不影响函数体外的变量
}
fun1 
echo $name
[root@shell day05]# sh fun.sh 
oldgirl
04.函数的返回值
`示例1`
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $1 ];then
        return 50
    else
        return 100
    fi
}
fun1 $1
[root@shell day05]# sh fun.sh /etc/hosts 
[root@shell day05]# echo $?
50
[root@shell day05]# sh fun.sh /etc/hostsssss
[root@shell day05]# echo $?
100

`示例2`
#根据返回结果判断、错误的方式,错误示例
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $1 ];then
        return 50
    else
        return 100
    fi
}
fun1 $1
[ $? -eq 50 ] && echo "$1 文件存在"
[ $? -eq 100 ] && echo "$1 文件不存在" #$?判断的上一条的执行结果
[root@shell day05]# sh fun.sh /etc/hosts
/etc/hosts 文件存在
[root@shell day05]# sh -x fun.sh /etc/hosts
+ fun1 /etc/hosts
+ '[' -f /etc/hosts ']'
+ return 50
+ '[' 50 -eq 50 ']'
+ echo '/etc/hosts 文件存在'
/etc/hosts 文件存在
+ '[' 0 -eq 100 ']'

`示例3:正确的写法`
[root@shell day05]# cat fun.sh 
#!/bin/bash
fun1(){
    if [ -f $1 ];then
        return 50
    else
        return 100
    fi
}
fun1 $1
re=$?
[ $re -eq 50 ] && echo "$1 文件存在"
[ $re -eq 100 ] && echo "$1 文件不存在" #$?判断的上一条的执行结果
[root@shell day05]# sh fun.sh /etc/hosts
/etc/hosts 文件存在
[root@shell day05]# sh fun.sh /etc/hostssss
/etc/hostssss 文件不存在
小结:函数推荐写法
#子函数
fun1(){
}
fun2(){
}
fun3(){
}
#主函数调用子函数
men(){
    fun1
    fun2
    fun3
}
#调用主函数
men
8.数组
数组介绍
语法结构:
        数组名称[下标]=值
        数值名称[元素名]=值
        数值名称[索引]=值
数组分类:
        普通数组:只能以数字作为索引
        关联数组:数字和字符串作为索引
变量:一个变量名中只能放一个值
比如:一个箱子对应一种水果
箱子1放的香蕉
箱子2放的黄瓜
箱子3放的苹果
name=oldboy

数组: 一个数组名中可以放多个值
比如: 一个箱子里放了很多盒子,每个盒子中放了一个水果
箱子[盒子1]=香蕉
箱子[盒子2]=黄瓜
箱子[盒子3]=苹果
name[1]=oldboy
name[2]=oldgirl
数组的定义方式

方法1:使用索引方式定义

#定义
[root@shell day05]# array[1]=shell
[root@shell day05]# array[2]=mysql
[root@shell day05]# array[3]=nginx

#查看值
[root@shell day05]# echo ${array[*]}
shell mysql nginx
[root@shell day05]# echo ${array[@]}    #和*相同
shell mysql nginx

#查看指定值
[root@shell day05]# echo ${array[1]}
shell
[root@shell day05]# echo ${array[2]}
mysql
[root@shell day05]# echo ${array[3]}
nginx

#查看数组索引
[root@shell day05]# echo ${!array[*]}
1 2 3

#使用declare查看定义好的数组
[root@shell day05]# declare -a|grep array
declare -a array=([1]="shell" [2]="mysql" [3]="nginx")  #自定义的

方法2:直接定义

[root@shell day05]# unset array     #取消数组、变量
[root@shell day05]# declare -a|grep array
[root@shell day05]# array=(a b c d e)
[root@shell day05]# echo ${array[*]}
a b c d e
[root@shell day05]# echo ${!array[*]}
0 1 2 3 4

方法3:支持命令

[root@shell day05]# unset array
[root@shell day05]# array=(`cat u.txt`)
[root@shell day05]# echo ${array[*]}
zs ef123.com li cd123.com lw ab123.com

方法4:混合定义

[root@shell day05]# array=([3]=a nginx [8]=b shell)
[root@shell day05]# echo ${array[*]}
a nginx b shell
[root@shell day05]# echo ${!array[*]}
3 4 8 9
案例1:将IP地址定义到数组、然后进行ping
`遍历数组`
[root@shell day05]# cat ping.sh 
#!/bin/bash
ip=(www.baidu.com www.sina.com 10.0.0.7 10.0.0.51)
for i in ${ip[*]}
do
    echo $i
done
[root@shell day05]# sh ping.sh 
www.baidu.com
www.sina.com
10.0.0.7
10.0.0.51

`数值遍历直接循环值`
[root@shell day05]# cat ping.sh 
#!/bin/bash
ip=(www.baidu.com www.sina.com 10.0.0.7 10.0.0.51)
for i in ${ip[*]}
do
    ping -c1 -W1 $i &>/dev/null
    [ $? -eq 0 ] && echo $i 在线...
done
[root@shell day05]# sh ping.sh 
www.baidu.com 在线...
www.sina.com 在线...
10.0.0.7 在线...

`数组遍历通过遍历索引`
[root@shell day05]# cat ping.sh 
#!/bin/bash
ip=(www.baidu.com www.sina.com 10.0.0.7 10.0.0.51)
for i in ${!ip[*]}
do
    ping -c1 -W1 ${ip[$i]} &>/dev/null
    [ $? -eq 0 ] && echo ${ip[$i]} 在线...
done
[root@shell day05]# sh ping.sh 
www.baidu.com 在线...
www.sina.com 在线...
10.0.0.7 在线...
9.关联数组

关联数组: 定义方式和普通数字相同的、区别是索引可以用字符串

示例
#shell中关联数组需要提前声明
[root@shell day05]# declare -A array
[root@shell day05]# array[index1]=a
[root@shell day05]# array[index2]=b
[root@shell day05]# array[index3]=c
[root@shell day05]# echo ${array[*]}
a c b
[root@shell day05]# echo ${!array[*]}
index1 index3 index2

[root@shell day05]# declare -A|grep array #查看临时定义的关联数组小a查看普通数组
declare -A array=([index1]="a" [index3]="c" [index2]="b" )
案例1:数组方式统计字符出现次数
[root@shell day05]# cat a.txt 
m
f
m
f
m
x
[root@shell day05]# declare -A array
[root@shell day05]# let array[m]++
[root@shell day05]# let array[f]++
[root@shell day05]# let array[m]++
[root@shell day05]# let array[f]++
[root@shell day05]# let array[m]++
[root@shell day05]# let array[x]++
[root@shell day05]# echo ${array[m]}
3
[root@shell day05]# echo ${array[f]}
2
[root@shell day05]# echo ${array[x]}
1

--------------------------
[root@shell day05]# cat array.sh 
#!/bin/bash
declare -A sex
for i in `cat a.txt`
do
    let sex[$i]++
done
for i in ${!sex[*]}
do
    echo $i出现了${sex[$i]}
done
[root@shell day05]# sh array.sh 
x出现了1
m出现了3
f出现了2

#数组的执行流程
#!/bin/bash
for i in `cat a.txt`  m  f m f m x
do      
     let sex[$i]++

     i=m
     let sex[m]++  sex[m]=1

     i=f
     let sex[f]++ sex[f]=1

     i=m
     let sex[m]++ sex[m]=2

done 
案例2:统计/etc/passwd文件中解释器出现次数
[root@shell day05]# cat array.sh 
#!/bin/bash
declare -A shell
while read line
do
    let shell[`echo $line|awk -F "[:/]+" '{print $NF}'`]++
done</etc/passwd

for i in ${!shell[*]}
do
    echo $i 出现了 ${shell[$i]}
done
[root@shell day05]# sh array.sh 
bash 出现了 1
nologin 出现了 36
halt 出现了 1
shutdown 出现了 1
sync 出现了 1
总结-速查表
流程控制:if then elif else fi case in esac
循环:for while until do done break continue
函数:function return exit

流程控制关键字

关键字 语法结构 作用
if if [条件]; then ... fi 条件判断
then 配合 if/elif 使用 判断成立后执行开始
elif if ...; then ... elif ...; then 否则如果(多条件分支)
else if ...; then ... else ... fi 否则(默认分支)
fi 结尾必须写 结束 if 语句
case case $var in ... esac 多值匹配
in 配合 case 使用 取值匹配
esac case 结尾 结束 case 语句

循环关键字

关键字 语法结构 作用
for for i in ...; do ... done 遍历循环
while while [条件]; do ... done 条件为真循环
until until [条件]; do ... done 条件为假循环
do 循环中间关键字 循环体开始
done 循环结尾 结束循环
break 循环内使用 跳出整个循环
continue 循环内使用 跳过本次循环

函数关键字

关键字 语法结构 作用
function function fun(){ ... } 定义函数(可选)
return 函数内使用 函数返回值
exit 任意位置 退出脚本 / 程序

输入输出 / 重定向关键字

关键字 / 符号 作用
echo 打印输出
read 读取输入
> 覆盖重定向
>> 追加重定向
< 输入重定向

Shell 内置特殊变量

变量 含义
$0 脚本名称
$n 脚本传参第n个参数,n为数字
$# 脚本传参的总个数
$? 上一条命令执行结果,0为成功,非0失败
$! 表示调用上一个在后台执行的脚本PID
$$ 脚本的PID号
$* 所有参数
$@ 所有参数(分开)
$_ 脚本的最后一个参数 类似esc .
shell面试题:
会shell吗?都写过什么shell脚本?
1.自动安装软件脚本(有软件需要编译的或者版本不同的写成脚本安装方便)
2.系统优化脚本(ssh 文件描述符 内核 防火墙..)
3.数据分析统计脚本(top10 日志)+定时任务+定时发送到相关人员邮件
4.日志切割脚本(防止日志过大)
5.在早的时候写过监控脚本(内存 磁盘 cpu 负载 服务 接口 服务状态...)异常发送企业微信 邮箱...
6.辅助运行程序脚本(程序运行过程出现各种问题,一时半会无法解决,比如磁盘干满了,内存干满了,程序自己挂了,我要写个脚本监控着他+定时任务)
nohup python3.0 test.py & ------->当前运行目录 nohup.out日志文件
正文完
 0
评论(没有评论)