内容目录

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脚本内部获取传入的位置参数,获取参数的格式为:$nn代表一个数字
例如传递给脚本的第一个参数为$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.登录页面是什么样子
#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%,则告警,否则没有任何提示
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.替换第一个HadoopLinux
    • 4.替换全部HadoopLinux
    • 用户输入数字1|2|3|4,可以执行对应项的功能
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
变量默认值
  1. ${var:-string}
    若变量var为空时,则用string作为变量var的值
    若变量var不为空时,则直接使用变量var的值

  2. ${var:=string}
    若变量var为空时,则用string作为变量var的值;(同时将string赋给变量var
    若变量var不为空时,则直接使用变量var的值
    ${var:=string}很常用的一种用法是,判断某个变量是否赋值,没有的话则给它赋上一个默认值

  3. ${var:+string}
    若变量var为空时,则不替换或者说是替换成var的值,即空值。(因为变量var此时为空,所以这两种说法是等价的)
    若变量var不为空时,则将string作为var变量的值,同时将string赋值给var变量

最后修改日期: 2024年10月7日

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。