Shell脚本编程

变量

  • 变量的定义

    • 变量名的命名规则

      • 字母、数字、下划线
      • 不以数字开头
  • 变量的赋值,不区分类型,等号两侧不允许出现空格

    • 为变量赋值的过程,称为变量替换

      • 变量名=变量值

        • a=123
      • 使用let为变量赋值

        • let a=10+20

          使用let可以计算等号右侧的值

      • 将命令赋值给变量

        • l=ls
      • 将命令结果赋值给变量,使用$()或者``

        • letc=$(ls -l /etc)

          将命令赋值给变量,通过访问变量去执行命令可以节省系统资源开销

      • 变量值有空格等特殊字符可以包含在””或’’中

  • 变量的引用

    • ${变量名}称作对变量的引用
    • echo ${变量名}查看变量的值
    • ${变量名}在部分情况下可以省略大括号,例如变量名后面没有跟其他字符的时候
  • 变量的作用范围

    • 默认作用范围

      • 定义变量的当前shell
    • 变量的导出

      • export 变量名

        可以使变量在其父进程shell和子进程shell都生效

    • 变量的删除

      • unset 变量名

        删除变量

  • 系统环境变量

  • 环境变量配置文件

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
定义数组

IPTS=( 10.0.0.1 10.0.0.2 10.0.0.3 )

显示数组的所有元素

echo ${IPTS[@]}

显示数组元素的个数

echo ${#IPTS[@]}

显示数组的第一个元素

echo ${IPTS[0]}

运算符

  • 赋值运算符

    • = 赋值运算符,用于算数赋值和字符串赋值
    • 使用unset取消为变量的赋值
    • = 除了作为赋值运算符还可以作为测试操作符
  • 算数运算符

    • 基本运算符

      • * + - * / ** %
    • 使用expr进行运算

      • expr 4 + 5

        符号左右要有空格,只支持整数,不支持浮点数

        num=`expr 4 + 5`

  • 数字常量

    • let “变量名=变量值”
    • 变量值使用0开头为八进制
    • 变量值使用0x开头为十六进制
  • 双圆括号

    • (( a=10 ))
    • (( a++ ))
    • echo $((10+20))
    • (( a=4+5 ))

test比较

  • 退出与退出状态

    • 退出程序命令

      • exit
      • exit 10 返回10给shell,返回值非0为不正常退出
      • $?判断当前shell前一个进程是否正常退出
  • 测试命令test

    • test命令用于检查文件或者比较值

    • test可以做以下测试

      • 文件测试
      • 整数比较测试
      • 字符串测试
    • test测试语句可以简化为[]符号

      • -z STRING

        字符串长度为0

      • STRING1 = STRING2

        字符串相等,区分大小写

      • STRING1 != STRING2

        字符串不相等,区分大小写

      • INTEGER1 -eq INTEGER2

        整数1等于整数2

      • INTEGER1 -ge INTEGER2

        整数1大于等于整数2,如果使用>=,需使用[[]]

      • INTEGER1 -gt INTEGER2

        整数1大于整数2,如果使用>,需使用[[]]

      • INTEGER1 -le INTEGER2

        整数1小于等于整数2,如果使用<=,需使用[[]]

      • INTEGER1 -lt INTEGER2

        整数1小于整数2,如果使用<,需使用[[]]

      • INTEGER1 -ne INTEGER2

        整数1不等于整数2

      • -e FILE

        文件存在,不区分文件和目录

      • -d FILE

        文件存在并且是一个目录

      • -f FILE

        文件存在并且是一个普通文件

    • []符号还有扩展写法[[]]支持&&、||、<、>

  • 使用if-then语句

    • if [ 测试条件成立 ] 或 命令返回值是否为0

    • then 执行相应命令

    • fi 结束

      代码示例:

      • 输出root
      1
      2
      3
      4
      5
       [root@localhost ~]# if [ $UID = 0 ]
      > then
      > echo root
      > fi
      root
      • 什么也没有输出
      1
      2
      3
      4
      5
      6
      [root@localhost ~]# su - vagrant
      Last login: 二 10月 22 02:11:36 UTC 2019 from 10.0.2.2 on pts/0
      [vagrant@localhost ~]$ if [ $UID = 0 ]
      > then
      > echo root
      > fi
      • 执行
      1
      2
      3
      4
      5
      6
        [vagrant@localhost ~]$ if pwd
      > then
      > echo success
      > fi
      /home/vagrant
      success
      • 未执行
      1
      2
      3
      4
      5
        [vagrant@localhost ~]$ if pwd1
      > then
      > echo success
      > fi
      -bash: pwd1: command not found
  • 使用if-then-else语句

    • 使用if-then-else语句可以在条件不成立时也运行相应的命令

      • if [ 测试条件成立 ]

      • then 执行相应命令

      • else 测试条件不成立,执行相应命令

      • fi 结束

        代码示例:

      • root用户

        1
        2
        3
        4
        5
        6
        7
        8
        9
        [root@localhost ~]# if [ $USER = root ] ; then
        > echo root user
        > echo $UID
        > else
        > echo other user
        > echo $UID
        > fi
        root user
        0
      • 普通用户

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        [root@localhost ~]# su - vagrant
        Last login: Wed Oct 23 03:59:20 UTC 2019 on pts/0
        [vagrant@localhost ~]$ if [ $USER = root ] ; then
        > echo root user
        > echo $UID
        > else
        > echo other user
        > echo $UID
        > fi
        other user
        1000
* 使用if-then-elif-then-else语句可以在条件不成立时也运行相应的命令

    * if [ 测试条件成立 ]
    * then 执行相应命令
    * elif [ 测试条件成立 ]
    * then 执行相应命令
    * else 测试条件不成立,执行相应命令
    * fi 结束

    
1
2
3
4
5
6
7
8
9
10
11
12
[vagrant@localhost ~]$ if [ $USER = root ] ; then
> echo root user
> echo $UID
> elif [ $USER = vagrant ] ; then
> echo vagrant user
> echo $UID
> else
> echo other user
> echo $UID
> fi
vagrant user
1000
  • 嵌套if语句

    • if条件测试中可以再嵌套if条件测试

      • if [ 测试条件成立 ]

      • then 执行相应命令

        • if [ 测试条件成立 ]
        • then 执行相应命令
        • fi
      • fi 结束

        代码示例:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        [vagrant@localhost ~]$ if [ $USER = root ] ; then
        > echo root user
        > echo $UID
        > else
        > if [ $USER = vagrant ] ; then
        > echo vagrant user
        > echo $UID
        > fi
        > echo other user
        > fi
        vagrant user
        1000
        other user
  • 分支

    • case 语句和select 语句可以构成分支

      • case “$变量” in

        • “情况1” )

          • 命令…
          • ;;
        • “情况2” )

          • 命令…
          • ;;
          • *)
          • 命令…
          • ;;
      • esac

        代码示例:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        #!/bin/bash

        # demo

        case "$1" in
        "START" | "start")
        echo $0 start...
        ;;
        "stop")
        echo $0 stop...
        ;;
        "restart" | "reload")
        echo $0 restart...
        ;;
        *)
        echo "Usage: $0 {start | stop | restart | reload}"
        ;;
        esac

循环

  • 使用 for 循环遍历命令的执行结果

    • for 循环的语法

      • for 参数 in 列表
      • do 执行的命令
      • done 封闭一个循环
    • 使用反引号或$()方式执行命令,命令的结果当做列表进行处理

  • 使用 for 循环遍历变量和文件的内容

    • 列表中包含多个变量,变量用空格分隔

    • 对文本处理,要使用文本查看命令取出文本内容

      • 默认逐行处理,如果文本出现空格会当做多行处理

      代码示例:

      1
      2
      3
      4
      5
      [root@localhost ~]# touch a.mp3 b.mp3 c.mp3
      [root@localhost ~]# for filename in `ls *.mp3`
      > do
      > mv $filename $(basename $filename .mp3).mp4
      > done
  • C 语言风格的 for 循环

    • for ((变量初始化;循环判断条件;变量变化))

    • do

      • 循环执行的命令
    • done

      代码示例:

      1
      2
      3
      4
      [root@localhost ~]# for ((i=1;i<=10;i++))
      > do
      > echo $i
      > done
  • while 循环

    • while test测试是否成立

    • do

      • 命令
    • done

      代码示例:

      1
      2
      3
      4
      5
      	[root@localhost ~]# while [ a -lt 10 ]
      > do
      > (( a++ ))
      > echo $a
      > done
  • 死循环

    代码示例:

    1
    2
    3
    4
    [root@localhost ~]# while :
    > do
    > echo hello
    > done
  • until 循环

    • until 循环与 while 循环相反,循环测试为假时,执行循环,为真时循环停止

      代码示例:

      1
      2
      3
      4
      5
      6
      [root@localhost ~]# a=1
      [root@localhost ~]# until [ $a -gt 5 ]
      > do
      > (( a++ ))
      > echo $a
      > done
  • break 和 continue 语句

    • 循环的使用

      • 循环和循环可以嵌套

      • 循环中可以嵌套判断,反过来也可以嵌套

      • 循环可以使用break和continue语句在循环中退出

        代码示例:

        • break

          1
          2
          3
          4
          5
          6
          [root@localhost ~]# for a in {1..9} ; do
          > if [ $a eq 5 ] ; then
          > break
          > fi
          > echo $a
          > done
        • continue

          1
          2
          3
          4
          5
          6
          [root@localhost ~]# for a in {1..9} ; do
          > if [ $a eq 5 ] ; then
          > continue
          > fi
          > echo $a
          > done
  • 使用循环对命令行参数的处理

    • 命令行参数可以使用 $1 $2 … ${10} … $n 进行读取

    • $0 代表脚本名称

    • $* 和 $@ 代表所有位置参数

    • $# 代表位置参数的数量

      代码示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      #!/bin/bash

      # demo

      # for pos in $*
      # do
      # if [ "$pos" = "hello" ] ; then
      # echo $pos $pos
      # fi
      # done

      while [ $# -ge 1 ]
      do
      if [ "$1" = "hello" ] ; then
      echo $1 $1
      fi
      shift
      done

函数

  • 自定义函数

    • 函数用于 ”包含“ 重复使用的命令集合

    • 自定义函数

      • function fname(){
      • 命令
      • }
    • 函数的执行

      • fname
    • 函数作用范围的变量

      • local 变量名
    • 函数的参考

      • $1 $2 $3 … $n

      代码示例:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      #!/bin/bash

      # demo

      checkpid() {
      local i
      for i in $* ; do
      [ -d "/proc/$i" ] && return 0
      done
      return 1
      }