ThankNeko's Blog ThankNeko's Blog
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)

Hoshinozora

尽人事,听天命。
首页
  • 操作系统

    • Linux基础
    • Linux服务
    • WindowsServer笔记
    • Ansible笔记
    • Shell笔记
  • 容器服务

    • Docker笔记
    • Kubernetes笔记
    • Git笔记
  • 数据库服务

    • MySQL笔记
    • ELK笔记
    • Redis笔记
  • 监控服务

    • Zabbix笔记
  • Web服务

    • Nginx笔记
    • Tomcat笔记
  • 数据处理

    • Kettle笔记
  • Python笔记
  • Bootstrap笔记
  • C笔记
  • C++笔记
  • Arduino笔记
  • 分类
  • 标签
  • 归档
  • 随笔
  • 关于
GitHub (opens new window)
  • 操作系统

    • Linux基础

    • Linux服务

    • Windows Server笔记

    • Shell笔记

      • Shell脚本介绍与变量
        • Shell脚本介绍
          • Shell简介
          • Shell脚本简介
          • Shell脚本的作用
          • Shell脚本规范
          • 脚本的执行方式
        • Shell脚本变量
          • 变量简介
          • Shell变量分类
          • 变量名称定义规范
          • 调用变量的方法
          • 变量值的类型
          • 内置变量
          • 交互式赋值
          • 变量替换
        • Shell数值运算
          • 整数运算
          • 小数运算
        • Shell数组
          • Shell数组介绍
          • 定义普通数组
          • 定义关联数组
          • 查看数组元素
          • 其他数组操作
      • Shell流程控制与函数
      • Shell脚本常见应用
    • Ansible笔记

  • 虚拟化服务

  • 数据库服务

  • 监控服务

  • Web服务

  • 数据处理

  • Ops
  • 操作系统
  • Shell笔记
Hoshinozora
2023-04-05
目录

Shell脚本介绍与变量

# Shell脚本介绍

# Shell简介

Shell是一个命令解释器,他在操作系统的最外层,负责翻译用户的命令给内核,并返回结果屏幕。他可以以两种方式执行命令:交互式和非交互式。

  • 交互式:日常使用最多的一种模式,比如登录终端、执行命令、返回结果等等,交互方式进行会话。
  • 非交互式:Shell不与用户直接交互,而是读取某个文件中的Shell命令进行执行,直到结束。

# Shell脚本简介

Shell脚本实际就是Shell命令的集合,将许多可执行的命令放在文本中成为Shell脚本,包括各种条件表达式、判断语句、数组、开头格式等。

学习Shell脚本一般需要掌握:环境变量、条件表达式、if判断、for循环、while循环、case语句、数组、流程控制等语句。

# Shell脚本的作用

Shell的主要作用是简化操作步骤,减少重复工作,减少系统故障,提高效率。

  • 基础配置
    • 系统初始化、系统更新、内核调整、网络、时区、SSH优化、加大文件描述符等。
  • 安装程序
    • 部署Nginx、MySQL、PHP、Sersync、NFS等各种服务。
  • 配置变更
    • nginx 、php、mysql、nfs、rsync等服务配置文件的修改。
  • 业务部署
    • Shell配合git、jenkins实现自动化部署php、java代码,或者配合link实现代码秒级回滚等操作。
  • 日常备份
    • 对MySQL、重要数据等,进行每天的全备与增量备份。
  • 信息采集
    • Zabbix+Shell实现对硬件、系统、服务、网络、等等的信息采集。
  • 日志分析
    • 取值 -> 排序 -> 去重 -> 统计 -> 分析。
  • 服务扩容
    • 监控服务器集群的CPU,如CPU负载均衡持续80% + 则触发动作(脚本)。
    • 脚本调用云厂商提供的API启动云主机 —> 初始化环境 —> 加入集群 —> 对外提供。
  • 服务缩容
    • 监控服务器集群的CPU,如CPU负载均衡低于20% -> 检测当前有多少web节点 -> 判断是否超过预设 -> 缩减到对应的预设状态 -> 变更负载的配置。

# Shell脚本规范

  1. 脚本存放在统一的目录,比如:/data/scripts/。

  2. 脚本开头第一行必须是#!/bin/bash或#!/bin/sh。

    • 绝大部分系统会将/bin/sh软链接到/bin/bash,因为bash比sh的功能更加全面。
  3. 脚本必须以.sh结尾。

  4. 脚本要有注释信息,注释尽量使用英文,但中文也行。

    • 脚本作者名、联系方式(邮箱、QQ等)、版本、时间、脚本作用、代码行的作用。

    • 例如:

      #!/bin/bash
      # Author:		Harmoniar
      # Mail:			test@qq.com
      # Version:		1.0
      # Date:			2023-04-02
      # Description:	This script is used to regularly clean up logs.
      
      # 清理xxx业务两天前的日志
      find /data/logs/xxx/ -ctime +2 -name "*.log.gz" -delete
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
  5. 成对的语句符号一次性写完,例如:if []...then...fi。

  6. 数值的比较要用-eq等,字符串的比较要用==。

  7. 重要操作要提示用户是否确认操作[Y/N],且提示要尽量的少而简洁。

  8. 文件路径等常用配置参数,尽量使用变量。

# 脚本的执行方式

  • 使用命令解释器执行,例如:bash [脚本路径]。
  • 使用路径执行脚本,例如:[脚本路径]。
    • 脚本需要有执行权限才能通过路径执行。
    • 如果不写开头的解释器注释#!/bin/bash,则默认会以bash解释器去执行脚本。
    • 如果写了开头的解释器注释#!/bin/bash,则会以指定的解释器去执行脚本。
    • 所以如果需要通过路径执行Python脚本等,则必须指定解释器路径。
  • 使用source或者.执行脚本,例如:. [脚本路径]。
    • 使用命令解释器或者路径执行脚本,都是创建一个子Shell来执行脚本。
    • 而使用source或者.方式执行脚本,则会在用户当前所在的Shell执行脚本。

# Shell脚本变量

# 变量简介

变量是传递数据的一种方式,就是用一个固定的字符其表示不固定的值,以便于后续引用。定义变量会在内存中分配一个变量空间用来存放数据。

# Shell变量分类

  • 普通变量
    • 就是仅针对当前Shell生效的局部变量。
    • 在Shell中执行定义命令即可,例如:Name="Harmoniar"
  • 环境变量
    • 就是针对所有Shell生效的变量,例如:export Name="Harmoniar"。
    • 定义临时环境变量直接在Shell中执行定义命令即可,重启后失效。
    • 定义永久环境变量则需要将环境变量定义在/etc/profile或/etc/bashrc文件中,然后通过source或.执行一次文件即可,重启后仍有效。
  • 用户自定义变量
    • 用户环境的变量,在用户登录时会自动定义的变量。
    • 在$HOME/.bashrc文件中定义普通变量即可。
  • 系统环境变量
    • 系统环境相关的变量。
    • 例如:$HOME、$PATH...
  • 位置参数变量
    • 向脚本中进行参数传递的变量,变量名不能自定义,变量作用也是固定的。
    • 例如:$1、$2、$3...
  • 内置变量
    • Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的。
    • 例如:$?、$0、$n、$$...

# 变量名称定义规范

  • 变量名要见名知其意。
  • 下划线、数字、字母的组合,需以字母或下划线开头,不能以数字开头。
  • 定义变量时,等号两边不能有空格。
  • 变量名不能是Shell关键字,例如:if、while等。
  • 命名例子:
    • girl_age - 下划线命名法
    • GIRL_AGE - 系统使用的命名法
    • girlAge - 小驼峰命名法
    • GirlAge - 大驼峰命名法

# 调用变量的方法

  • 直接调用
    • 例如:echo "$var"
  • 调用的变量后面接字符
    • 将变量名用{}括起来,将其作为一个整体。
    • 例如:echo "${变量名}_test"
  • 使$变成普通字符不解析
    • $符号前加反斜杠\即可,例如:echo "\$test"。
    • 或者使用'单引号包裹字符串,不解析变量,例如:echo '$test'。
  • 调用系统变量
    • 通过export命令可查看已定义的环境变量,然后直接调用即可。

# 变量值的类型

  • 定义数值

    • 变量定义的数值必须是连续的数字。

    • 例如:test=123456

  • 定义字符串

    • 定义字符串需要加引号,如果加的是"双引号则会解析其中的特殊符号,如果加的是'单引号则会将内容全部作为普通字符串。

    • 例如:test="my name is $NAME"

  • 定义命令值

    • 定义的命令值变量,会将命令执行的返回结果复制给变量。

    • 以下两种方式作用相同,都是创建一个子Shell来执行命令并获取返回结果。

      # 使用``解析命令
      test=`date`
      # 使用$()解析命令
      test=$(date)
      
      1
      2
      3
      4

# 内置变量

  • $0 - 代表脚本的名称

    • 如果是绝对路径执行,则脚本名将为绝对路径。

    • 可用于提示用户该怎样正确使用脚本,例如:

      echo "Usage: $0 {start|stop|restart}"
      >Usage: /scripts/test.sh {start|stop|restart}
      
      1
      2
  • $n - 传入脚本的第n个参数

    • 代表用户执行脚本时传递的参数,例如: sh test.sh [参数1] [参数2]...
    • n代表传入脚本的第n个位置参数,例如:$1、$2、$3...
    • $9以上的参数需要加{}以将数值视为一个整体,例如: ${11}
  • $# - 获取脚本传参的总个数

    • 可用于控制脚本的传参个数,例如:

      if [ $# -ne 2 ] && echo "请输入两个参数" && exit
      
      1
  • $ - 获取脚本所有的参数*

    • 在脚本中$*与$@作用相同。

    • 在循环体中,不加双引号和$@相同,将以空格为分隔进行迭代,例如:

      for i in $*;do
          echo $i
      done
      
      > test.sh "I am" HaHa
      # 输出:
      > I
      > am
      > HaHa
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
    • 在循环体中,加上双引号则把所以参数视为一个参数$1 $2 ...,例如:

      for i in "$*";do
          echo $i;
      done
      
      > test.sh "I am" HaHa
      # 输出:
      I am HaHa
      
      1
      2
      3
      4
      5
      6
      7
  • $@ - 获取脚本所有的参数

    • 在脚本中$*与$@作用相同。

    • 在循环体中,不加双引号和$*相同,将以空格为分隔进行迭代。

    • 在循环体中,加上双引号则把每个参数视为正常独立的参数$1 $2 ...,例如:

      for i in "$@";do
          echo $i;
      done
      
      > test.sh "I am" HaHa
      # 输出:
      I am
      HaHa
      
      1
      2
      3
      4
      5
      6
      7
      8
  • $? - 获取上一条命令的返回值

    • Linux中的规范是,成功返回0,失败返回非0。
    • exit [返回值] - 值需要在0~255之间,脚本中一般会使用的结束脚本并返回值的操作。
  • $$ - 获取脚本的PID

    • 借助该变量,我们可以在开始时创建脚本的pid文件,例如:

      # 脚本开始执行时
      echo $$ > /tmp/test.pid
      
      # 脚本结束执行时
      rm -f /tmp/test.pid
      
      # pid文件可以用于判断脚本是否在运行,如果已经有在运行则返回不能重复运行。
      # 也可以用于杀进程 kill -9 `cat /tmp/test.pid`
      
      1
      2
      3
      4
      5
      6
      7
      8
  • $! - 获取上一个在后台运行的脚本的PID

    • 一般在调试时才会用到,我们也可以使用该变量杀掉上一个脚本进程kill $!。
  • $_ - 获取命令行最后一个参数

    • 例如传入的位置参数有$1 $2 $3,那么$_就等于$3。

# 交互式赋值

  • 主要通过read命令进行实现,我们可以将用户交互式输入的信息传递给变量。

  • 例如:

    # -p参数可以在读取前先打印一条信息
    # 用户输入信息并回车后,会将用户输入的信息作为值传递给变量
    read -p "提示信息:" 变量名
    
    # 用户也可以一次输入多个变量,输入的变量需要以空格隔开
    read -p "提示信息:" 变量名 变量名...
    
    1
    2
    3
    4
    5
    6

# 变量替换

  • 匹配变量的值,然后将匹配的内容删除或替换,但不会实际修改变量本身。

  • 删除

    • $(变量#匹配规则) - 从左往右匹配,非贪婪匹配
      • 例如:echo ${TEST#*c}会将*c匹配的内容删除然后显示。
    • $(变量##匹配规则) - 从左往右匹配,贪婪匹配
    • $(变量%匹配规则) - 从右往左匹配,非贪婪匹配
    • $(变量%%匹配规则) - 从右往左匹配,贪婪匹配
  • 替换

    • $(变量/旧字符串/新字符串) - 从左往替换字符串,只替换一次
    • $(变量//旧字符串/新字符串) - 从左往替换字符串,全部替换
  • 其他

    • ${#变量} - 获取变量字符串的长度

      • 同等于echo $var | wc -L。
    • ${变量:开始索引:结束索引} - 截取变量字符串的内容

      • 索引从0开始,没有开始或结束的索引时,则将从0、$开始或结尾。

      • 例如:

        test=12345
        echo ${test:0:2}
        > 12
        
        1
        2
        3

# Shell数值运算

# 整数运算

  • 整数运算将会省略小数点后面的数值。
  • expr
    • 需要用空格隔开,且特殊字符需要转义 如\*。
    • 例如:expr 1 + 1
  • $(())
    • 将$(())内的数值进行运算,另外也可以写成$[]。
    • 例如:echo "this is $((2+1))"

# 小数运算

  • 可以使用awk命令来进行运算。
    • 例如:awk "BEGIN{print 1/2}"
  • awk调用shell变量方法
    • awk 'BEGIN{print "'$var'"}' - "'$var'" 双引号内扩上单引号进行引用
    • awk -v nvar="$var" '{print nvar}' - 使用-v将shell变量传递给awk变量

# Shell数组

# Shell数组介绍

  • Shell的数组也算是变量,区别在于变量只能存储一个值,而数组可以存储多个值。

  • Shell数组可以分为两类:普通数组和关联数组

    • 普通数组只能使用整数作为数组索引,类似于Python的列表,例如:

      test=(one two three four five)
      echo ${test[0]}
      
      1
      2
    • 关联数组只能使用字符串作为数组索引,类似于Python的字典,例如:

      declare -A test
      test=([name]=one [age]=18)
      echo ${test[name]}
      
      1
      2
      3

# 定义普通数组

  • 数组名[数值索引]=值 - 一次定义单个值

    • 如果数组或元素原本不存在则会创建,例如:test[0]="one"

    • Shell数组的索引可不按顺序,所以我们可以赋值给不存在的索引,例如:

      test=(one two three)
      test[8]=eight
      # 此时test的索引就为0 1 2 8
      
      1
      2
      3
  • 数组名=(元素1 元素2 元素3...) - 一次定义多个值

    • 例如:

      # 一次定义多个值
      test=(one two "I am Shell")
      
      # 也可以指定索引定义
      test=(one two [6]=six)
      
      1
      2
      3
      4
      5
  • 数组名=(`命令`) - 命令定义多个值

    • 会将命令的执行结果以空白符作为分隔符,按顺序赋值给索引,空白字符也就是\n、\t、空格。

    • 例如:

      test=(`date`)
      # 同等于
      test=($(date))
      
      1
      2
      3

# 定义关联数组

  • declare -A [关联数组名] - 定义关联数组需要先进行声明
  • 数组名[字符串索引]=值 - 一次定义单个值
    • 如果数组或元素原本不存在则会创建,例如:test[name]="one"
  • 数组名=([键名1]=值 [键名2]=值 [键名3]=值 ...) - 一次定义多个值
    • 例如:test=([name]="one" [age]=18)

# 查看数组元素

  • ${数组名[索引]} - 访问数组中的元素

    # 访问普通数组元素
    echo ${test[0]}
    
    # 访问关联数组元素
    echo ${test[name]}
    
    1
    2
    3
    4
    5
  • ${数组名[@]} - 列出数组的所有元素

    # 列出数组中的所有元素,[@]和[*]作用一致
    echo ${test[@]}
    echo ${test[*]}
    
    1
    2
    3
  • ${!数组名[@]} - 列出数组的所有索引

    # 列出数组中的所有索引,[@]和[*]作用一致
    echo ${!test[@]}
    echo ${!test[*]}
    
    1
    2
    3
  • ${#数组名[@]} - 列出数组的元素总数

    # 列出数组的元素总数
    echo ${#test[@]}
    
    1
    2

# 其他数组操作

  • declare -a - 查看所有普通数组

  • declare -A - 查看所有关联数组

  • unset [数组名] - 取消定义数组

#Linux#Shell
深信服桌面云
Shell流程控制与函数

← 深信服桌面云 Shell流程控制与函数→

最近更新
01
二〇二五年四月十七日随笔
04-17
02
二〇二五年四月十六日随笔
04-16
03
二〇二五年四月九日随笔
04-09
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Hoshinozora | MIT License
湘ICP备2022022820号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式