Shell编程
一、Shell介绍-day054
1.shell学习大纲
- 入门、规范
- shell执行方式
- 变量基础
- 变量子串
- 核心位置变量
- 数值比对
- 字符串比对
- 文件判断
- if判断
- case语句
- for循环
- while循环
- 流程控制 exit continue break
- 函数
- 数组
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日志文件