Shell脚本概述
什么是shell
shell
是一个命令解释器,它在操作系统的最外层,负责直接与用户进行对话,将用户输入的命令翻译给操作系统,并将处理的结果输出至屏幕- 当然
shell
命令是存在交互式、非交互式两种方式- 交互:日常使用、登录、执行命令、退出;
- 非交互:直接读取某个文件,文件从头执行到尾即结束
什么是shell脚本
- 1.将系统命令堆积在一起,顺序执行(简称:系统命令堆积)
- 2.特定的格式+特定的语法+系统的命令=文件(Shell脚本文件)
- 开头:
#!/usr/bin/bash
- 语法:
if for ...
awk,grep,sed...
- 开头:
Shell脚本能做什么
- 1.基础配置:系统初始化操作、系统更新、内核调整、网络、时区、SSH优化
- 2.安装程序:部署
lnmp、lnmt、mysql、nginx、redis、lvs、keepalived
等待 - 3.配置变更:
nginx conf、php conf、mysql conf、redis conf
- 4.业务部署:
shell
配合git、jenkins
实现代码自动部署,以及代码回滚 - 5.日常备份:使用
shell
脚本对mysql
进行每晚的全备与增量备份 - 6.信息采集:
zabbix + shell
,硬件、系统、服务、网络等待 - 7.日志分析:取值-->排序-->去重-->统计-->分析
- 8.服务扩容:扩容监控服务集群
cpu
,如cpu
负载持续80% + 触发动作(脚本),脚本:调用api
开通云主机-->初始化环境-->加入集群-->对外提供 - 9.服务缩容:监控服务集群
cpu
使用率,低于20%-->检测当前有多少web
节点-->判断是否超过预设-->缩减到对应的预设状态-->变更负载的配置 - 10.字符提取:比如
nginx
状态、php
状态、格式化数据等 - 注意:
shell
脚本主要的作用是简化操作步骤,提高效率,减少人为干预,减少系统故障
Shell脚本预备知识
学习shell脚本预备知识
- 1.熟练使用
vim
编辑器 - 2.熟练使用
linux
基础命令(awk,grep,wc,netstat,ps,lsof,find...
) - 3.数量使用
linux
三剑客 - 注意:如果我们对命令使用不够熟练,对基本服务也不会手动搭建,那么一定学不会
shell
如何才能学好shell脚本
- 1.基础命令+基础服务+练习+思路(必备)
- 2.能看懂
shell
脚本-->能修改shell
脚本-->能编写shell
脚本-->能优化shell
脚本
Shell脚本书写方式
Shell脚本命名规范
- 名字要有意义,不要使用
a、b、c、1、2、3
这种方式命名 - 虽然
linux
系统中,文件没有扩展名的概念- 依然建议使用
.sh
结尾 - 名称控制在30个字节以内。例如:
check_memory.sh
- 依然建议使用
Shell脚本格式申明
shell
脚本开头必须指定脚本运行环境以#
这个特殊符号组合来组成- 如:
#!/bin/bash
指定该脚本是运行解析由/bin/bash
来完成
Shell脚本#号的使用
#!/bin/bash
#Author:xxx
#Created Time:2024/5/2 13:00
#Script Description: first shell study script
自动添加Shell的首部
cat ~/.vimrc
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1,"#!/usr/bin/bash")
call setline(2,"#****************************************")
call setline(3,"#Author : yujing")
call setline(4,"#Date : ".strftime("%y-%m-%d"))
call setline(5,"#FileName : ".expand("%"))
call setline(6,"#Description : The test script")
call setline(7,"#****************************************")
call setline(8,"")
endif
endfunc
autocmd BufNewFile * normal G
Shell变量
什么是变量
- 变量是
shell
中传递数据的一种方法 - 简单理解:就是用一个固定的字符串去表示不固定的值,便于后续引用
变量命名规范
- 变量定义命名:大写小写字母、下划线、数字组成,尽量字母开头。(变量名称最好具备一定含义)
- 变量定义语法:变量名=变量值,等号是赋值,需要注意:等号两边不能有空格,其次定义的变量不要与系统命令出现冲突。参考如下定义变量方式:
ip=10.0.0.100
ip1=10.0.0.100
Hostname_Ip=10.0.0.100
hostname_ip=10.0.0.100
system_cpu_load_avg1、system_cpu_load_avg5、system_cpu_load_avg15
变量定义方式
- 1.用户自定义变量:人为定义变量名与变量的值
- 2.系统环境变量:保存的是和系统操作环境相关的数据,所有用户都可以使用
- 3.位置参数变量:向脚本中进行参数传递,变量名不能自定义,变量作用是固定的
- 4.特殊参数变量:是
bash
中已经定义好的变量,变量名不能自定义,变量作用也是固定的
用户自定义变量
1.定义变量,变量名=变量值
var=“hello shell"
# 定义变量有空格必须使用双引号
2.引用变量,$变量名
或${变量名}
var="hello world"
echo $var
hello world
echo $var_log
echo ${var}_log
hello world_log
3.注意事项,应用变量时注意事项,""
双引号属于弱引用,''
单引号属于强引用
# var=iphone
echo "$var is good"
iphone is good
echo '$var is good'
$var is good
# 如果有变量的情况下,建议增加双引号
# 如果存在特殊的字符,不希望被解析,这个时候需要使用''或者转义字符\
echo \$var is good
系统环境变量
1.使用系统已定义好的环境变量
cat env.sh
#!/usr/bin/bash
echo "用户的家目录:$HOME"
echo "当前主机名是:$HOSTNAME"
echo "当前所在目录:$PWD"
bash env.sh
用户的家目录:/root
当前主机名是:wordpress
当前所在目录:/root
2.人为定义环境变量:export
变量,将自定义变量转换成环境变量
var=hello
echo $var
hello
cat hello.sh
#!/usr/bin/bash
echo $var
sh hello.sh # 执行hello.sh时,会使用另一个bash去执行,就访问不到$var的值
export var=hello # 将变量转换为环境变量
sh hello.sh # 再次执行脚本
hello
# 注意:也是临时的,退出该shell后不生效
位置参数变量
位置参数顾名思义,就是传递给脚本参数的位置,例如给一个脚本传递一个参数,我们可以在shell
脚本内部获取传入的位置参数,获取参数的格式为:$n
。n
代表一个数字
例如传递给脚本的第一个参数为$1
,第二个参数就为$2
,以此类推...,其中$0
为该脚本的名称
1.编写脚本
cat args.sh
echo "#当前shell脚本的文件名:$0"
echo "#第一个shell脚本位置参数:$1"
echo "#第二个shell脚本位置参数:$2"
echo "#第三个shell脚本位置参数:$3"
2.执行脚本(发现第一个参数11、第一个参数22、第三个参数33、脚本名称args.sh
)
sh args.sh 11 22 33
#当前shell脚本的文件名:args.sh
#第一个shell脚本位置参数:11
#第二个shell脚本位置参数:22
#第三个shell脚本位置参数:33
特殊参数变量
- 特殊参数:
$#
:传递给脚本或函数的参数个数总和$*
:传递给脚本或函数的所有参数,当被双引号""
包含时,所有的位置参数被看作一个字符串$@
:传递给脚本或函数的所有参数,当被双引号""
包含时,每个位置参数被看作独立的字符串$?
:上个命令的退出状态,或函数的返回值,0为执行成功,非0则为执行失败$$
:当前程序运行的PID
$0
:脚本的位置+名称=路径$1..$n
:脚本的位置参数,参数之间使用空格隔开
1.编写脚本
cat args.sh
#!/usr/bin/bash
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "脚本名称为:$0"
echo "脚本接收参数总数为:$#"
curl -I baidu.com &> /dev/null
echo "运行命令的状态为:$?"
echo "脚本的PID为:$$"
echo "\$* 的结果为:$*"
echo "\$@ 的结果为:$@"
echo "========================="
echo "\$* 循环接收的结果"
for i in "$*"
do
echo $i
done
echo "\$@ 循环接收的结果"
for j in "$@"
do
echo $j
done
2.执行脚本
sh args.sh jenkins docker kubernetes
第一个参数为:jenkins
第二个参数为:docker
脚本名称为:args.sh
脚本接收参数总数为:3
运行命令的状态为:0
脚本的PID为:98537
$* 的结果为:jenkins docker kubernetes
$@ 的结果为:jenkins docker kubernetes
=========================
$* 循环接收的结果
jenkins docker kubernetes
$@ 循环接收的结果
jenkins
docker
kubernetes
参数场景示例
需求1:通过位置变量创建linux
系统账号及密码,执行useradd.sh username password
cat ./variable/useradd.sh
# $1是执行脚本的第一个参数,$2是执行脚本的第二个参数
useradd $1
echo "$2" | passwd --stdin $1
需求2:通过位置变量创建linux
系统账号及密码,执行useradd.sh username password
,控制最多传递两个参数
cat ./variable/useradd.sh
# 判断传递的参数总个数
if [ $# -ne 2 ];then
echo "USAGE $0 [ UserName && Password]"
exit
fi
# 执行业务逻辑
# $1是执行脚本的第一个参数,$2是执行脚本的第二个参数
useradd $1
echo "$2" | passwd --stdin $1
需求3:通过位置变量创建linux
系统账号及密码,执行useradd.sh username password
,控制最多传递两个参数,且必须是root身份
cat ./variable/useradd.sh
#!/usr/bin/bash
if [ $UID -ne 0 ];then
echo "$USER Permission Deny! Please Use Root User..."
exit
fi
# 判断传递的参数总个数
if [ $# -ne 2 ];then
echo "USAGE $0 [ UserName && Password]"
exit
fi
# 执行业务逻辑
# $1是执行脚本的第一个参数,$2是执行脚本的第二个参数
useradd "$1"
echo "$2" | passwd --stdin "$1"
read交互传递变量
- 除了自定义变量,以及系统内置变量,还可以使用
read
命令通过交互方式传递变量
read选项 | 选项含义 |
---|---|
-p | 打印信息 |
-t | 限定时间 |
-s | 不回显 |
-n | 指定字符个数 |
- 1.
read
示例语法
cat read.sh
#!/usr/bin/bash
echo -n "Login: "
read acc
echo -n "Passwd: "
read pw
echo "account: $acc password: $pw"
- 2.
read -p
示例
cat read_2.sh
#!/usr/bin/bash
read -p "Login: " acc
read -p "Passwd: " pw
echo "account: $acc password: $pw"
- 3.
read -p -t -n -s
示例,限制用户输入密码超时5s
,密码密文,位数不能超过6
cat read_3.sh
#!/usr/bin/bash
read -p "Login: " acc
read -s -t5 -n6 -p "Passwd: " pw
echo "account: $acc password: $pw"
场景1-模拟登录页面脚本
- 使用
read
模拟linux
登录页面- 1.如果输入用户为
root
,密码为123,则输出欢迎登录 - 2.否则输出用户或密码错误
- 1.如果输入用户为
#1.登录页面是什么样子
#2.交互方式让其输入对应的用户名+密码
#3.判断输入的用户+密码是否正确
cat ./variable/login.sh
#!/usr/bin/bash
System=$(hostnamectl | awk '/Operating/' | awk -F ': ' '{print $NF}')
Kernel=$(hostnamectl | awk '/Kernel/' | awk -F '[: ]+' '{print $2}')
Kernel_version=$(hostnamectl | awk '/Kernel/' | awk -F '[: ]+' '{print $4}')
# 打印系统信息
echo $System
echo "$Kernel $Kernel_version on an $(uname -m)"
# 交互输入
read -p "$(hostname) login: " user
read -s -p "Password: " pass
echo ""
# 判断用户输入的用户名+密码是否正确
if [ $user == "root" -a $pass == "123" ];then
echo "欢迎 $user 用户登录节点..."
else
echo "用户密码错误..."
exit
fi
场景2-系统备份脚本
- 使用
read
编写一个备份脚本,需要用户传递2个参数,源和目标- 1.提示用户,你需要备份的文件在哪个路径下
- 2.提示用户,你要备份到哪个目录
- 3.你确定要备份吗?[ yes | no ]
- 4.如果输入
yes
就进行备份的操作,如果输入no
则取消备份
cat backup.sh
#!/usr/bin/bash
cat <<EOF
################################################
################Backup Scripts##################
################################################
EOF
read -p "你要备份的源文件在哪里:" src_file
read -p "你要备份到哪个目录下:" dest_dir
read -p "你要备份的源文件 $src_file 要备份到 $dest_dir 你确定吗?[ yes | no ]:" Action
if [ $Action == "yes" ];then
cp -rpv $src_file $dest_dir
else
exit
fi
场景3-探测主机存活脚本
- 使用
read
编写一个探测主机存活脚本,需要用户传递测试的IP
地址
cat ping.sh
#!/usr/bin/bash
read -p "请输入你要探测的IP地址:" Ip
ping -W 1 -c 1 $Ip &> /dev/null
if [ $? -eq 0 ];then
echo -e "\e[32m $Ip 通... \e[0m"
else
echo -e "\e[31m $Ip 不通... \e[0m"
fi
场景4-修改主机名称脚本
- 使用
read
编写一个修改系统主机名称的脚本- 1.打印当前主机名称
- 2.询问用户需要修改的新主机名称是什么
- 3.你是否要将旧的主机名称-->新的主机名称 [ yes | no]
- 4.调用
shell
命令执行修改
cat hostname.sh
#!/usr/bin/bash
old_host=$(hostname)
echo "当前主机名称是 ${old_host} "
read -p "你要修改的新主机名称是:" new_host
read -p "你要将 $old_host --> $new_host: [ yes | no ]" Action
if [ $Action == "yes" ];then
hostnamectl set-hostname $new_host
fi
Shell变量删除
什么是变量删除
简单来说,就是在不改变原有变量的情况下,对变量值进行删除
为什么要用变量删除
比如:我们需要对某个变量的值进行整数比对,但变量的值是一个小数,怎么办?
我们可以使用变量删除的方式,将小数位进行删除,然后再进行整数比对
变量删除的几种方式
变量 | 说明 |
---|---|
${变量#匹配规则} | 从头开始匹配,最短删除 |
${变量##匹配规则} | 从头开始匹配,最长删除 |
${变量%匹配规则} | 从尾开始匹配,最短删除 |
${变量%%匹配规则} | 从尾开始匹配,最长删除 |
变量删除语法示例
示例1:从前往后删除变量内容
url=www.sina.com.cn # 定义变量
echo ${url} # 输出变量的值
www.sina.com.cn
echo ${url#*.} # 从前往后,最短匹配
sina.com.cn
echo ${url##*.} # 从前往后,最长匹配
cn
示例2:从后往前删除变量内容
url=www.sina.com.cn # 定义变量
echo ${url} # 输出变量的值
www.sina.com.cn
echo ${url%.*} # 从后往前,最短匹配
www.sina.com
echo ${url%%.*} # 从后往前,最长匹配
www
场景1-提取内存百分比脚本
- 查看内存当前使用状态,如果使用率超过80%则告警
- 1.如何获取内存指标:
free -m
- 2.拿到使用率的百分比:
free -m | awk '/^Mem/ {print $3/$2*100}'
- 3.与定义的阈值80%做比对
- 4.超过80%,则告警,否则没有任何提示
- 1.如何获取内存指标:
cat memory_use.sh
#!/usr/bin/bash
Mem_Use=$(free -m | awk '/^Mem/ {print $3/$2*100}')
if [ ${Mem_Use%.*} -ge 9 ]
then
echo "Memory is error ${Mem_Use}%"
else
echo "Memory is ok ${Mem_Use}%"
fi
场景2-为不同版本系统安装源
写一个脚本,在cetos6
系统上运行安装6的epel
,在centos7
系统运行则安装7的epel
1.判断系统的版本:cat /etc/redhat-release | awk '{print $(NF-1)}'
2.根据不同的版本安装不同的源
cat epel.sh
#!/usr/bin/bash
system_version=$(cat /etc/redhat-release | awk '{print $(NF-1)}')
# -ne 不等于 -eq 等于
if [ ${system_version%%.*} -eq 7 ];then
wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo &> /etc/null
echo "centos ${system_version} epel OK"
fi
if [ ${system_version%%.*} -eq 6 ];then
wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-archive-6.repo &> /etc/null
echo "centos ${system_version} epel OK"
fi
Shell变量替换
什么是变量替换
简单来说,就是在不改变原有变量的情况下,对变量进行替换
比如:原本输出linux
是小写,可以将其转为LINUX
大写,或者直接删除
变量替换的方式
变量 | 说明 |
---|---|
${变量/旧字符串/新字符串} | 替换变量内的旧字符串为新字符串,只替换第一个 |
${变量//旧字符串/新字符串} | 替换变量内的旧字符串为新字符串,全部替换 |
场景1-替换PATH变量
- 如何替换
$PATH
中的/bin
替换为/BIN
echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/.local/bin:/root/bin
# 替换操作
echo ${PATH//bin/BIN}
/usr/local/sBIN:/usr/local/BIN:/usr/sBIN:/usr/BIN:/root/.local/BIN:/root/BIN
场景2-字符串替换脚本
- 需求:变量
string="Bigdata process is Hadoop,Hadoop is open source project"
执行脚本后,打印输出string
变量,并给出用户以下选项- 1.打印
string
长度 - 2.删除字符串中所有的
Hadoop
- 3.替换第一个
Hadoop
为Linux
- 4.替换全部
Hadoop
为Linux
- 用户输入数字
1|2|3|4
,可以执行对应项的功能
- 1.打印
cat replace.sh
#!/usr/bin/bash
string="Bigdata process is Hadoop, Hadoop is open source project"
echo $string
echo "1)、打印string长度"
echo "2)、删除字符串中所有的Hadoop"
echo "3)、替换第一个Hadoop为Linux"
echo "4)、替换全部Hadoop为Linux"
read -p "请输入对应的选项 [ 1 | 2 | 3 | 4 | ]" Action
if [ $Action -eq 1 ];then
echo "字符串的长度是:${#string}"
fi
if [ $Action -eq 2 ];then
echo "${string//Hadoop/}"
fi
if [ $Action -eq 3 ];then
echo "${string/Hadoop/Linux}"
fi
if [ $Action -eq 4 ];then
echo "${string//Hadoop/Linux}"
fi
Shell变量运算
什么是变量运算
- 其实就是我们以前学习过的 加 减 乘 除
为什么需要变量运算
- 当我们需要开发一个计算器程序时,是不是就需要运算了?
- 当我们要对结果进行单位换算时,是不是就需要变量运算了?
变量运算实现的方式
- 通常整数运算有
expr、$(())、$[]
等方式,小数运算有bc、awk
方式
操作符 | 含义 |
---|---|
num1 + num2 | 加 |
num1 - num2 | 减 |
num1 * num2 | 乘 |
num1 / num2 | 除 |
num1 % num2 | 余 |
- 定义变量,使用
expr、$(())、$[]
进行加减乘除。expr
必须空格隔开num1=10 num2=20 expr $num1 + $num2 30 echo $(( $num1 + $num2 )) 30 echo $[ $num1 + $num2 ] 30
场景1-根据当前时间计算明年时间
- 根据系统时间,打印今年和明年时间
echo "This is $(date +%Y) year"
This is 2024 year
echo "This is $[ $(date +%Y) +1 ] year"
This is 2025 year
场景2-计算今年还剩下多少周
- 需求:根据系统时间获取今年还剩下多少兴趣,已经过了多少星期。思路如下:
echo "今年已经过了 $(date +%j) days"
今年已经过了 125 days
echo "今年已经过了 $[ $(date +%j)/7 ] weeks"
今年已经过了 17 weeks
echo "今年还剩下 $[ (365 - $(date +%j))/7 ] weeks"
今年还剩下 34 weeks
变量默认值
-
${var:-string}
若变量var
为空时,则用string
作为变量var
的值
若变量var
不为空时,则直接使用变量var
的值 -
${var:=string}
若变量var
为空时,则用string
作为变量var
的值;(同时将string
赋给变量var
)
若变量var
不为空时,则直接使用变量var
的值
${var:=string}
很常用的一种用法是,判断某个变量是否赋值,没有的话则给它赋上一个默认值 -
${var:+string}
若变量var
为空时,则不替换或者说是替换成var
的值,即空值。(因为变量var
此时为空,所以这两种说法是等价的)
若变量var
不为空时,则将string
作为var
变量的值,同时将string
赋值给var
变量
留言