Files
rikako-note/linux/shell.md
2022-04-10 00:43:15 +08:00

9.0 KiB
Raw Blame History

Shell脚本编程

shell脚本结构

  • shell脚本头部:
    在shell脚本中首行通过 #!bin/bash 来指定该shell脚本所使用的语法和执行的shell环境。
    #!/bin/bash
    #除了首行之外,其他以'#'开头的行均为注释,在执行时会被忽略
    
  • 程序体:
    程序体中包含了该脚本的具体执行逻辑并且在执行结束后通过exit命令来返回该脚本的执行执行结果。
    #用exit命令来返回脚本的执行状态若返回值status为0,代表正常退出
    exit status
    

Shell语法

  • 输出shell脚本中定义的变量或是环境变量
    可以通过${VARNAME}的形式来输出变量的值,例如:

    #注意”“和‘’的区别,
    #   当使用”“来包围字符串时,字符串中的$(expression)和${varname}
    #       都会被替换为变量值和执行结果
    #   而当使用‘’来包围字符串时,$(expression)和${varname}并不会被
    #       替换为执行结果,而是以字面量的形式输出
    echo "PATH VALUE IS : ${PATH}
    
  • ${expr}的使用:

    1. 字符串的摘取:

      • '#'符号用来去掉左前缀的部分,’#‘作用于于第一个匹配,’##‘作用于最后一个匹配
      #设置路径为/var/log/mysql.log
      export VARPATH=/var/log/mysql.log
      
      #通过 '#*/'去掉第一'/'字符之前的子串
      #输出结果为var/log/mysql.log
      echo ${VARPATH#*/}
      
      #通过'##*/'来去掉最后一个'/'字符之前的子串
      #输出结果为mysql.log
      echo ${VARPATH##*/}
      
      • '%'符号用来去掉右后缀的部分,'%'作用于从右往左的第一条匹配,而'%%'则作用于从右往左的最后一条匹配
      #通过'%/*'可以去除最后一个'/'字符之后的部分
      #输出结果为/var/log
      echo ${VARPATH%/*}
      
      #通过'%%/*'可以删除第一个’/'之后的部分
      #结果为空串
      echo ${VARPATH%%/*}
      
      • 可以通过'${${expr1}expr2}'对前一次的操作结果进行再一次操作,例如
      #设置路径为/etc/init.d/idea.tar.gz
      export VARPATH=/etc/init.d/idea.tar.gz
      
      #截取文件扩展名tar.gz
      #输出结果为tar.gz
      echo ${${VARPATH##*/}#*.}
      
    2. 字符串子串的截取和替换

      • ${STR:from:len}可以截取字符串从第from个字符开始长度为len的子串
      export STR=/var/log/mysql.log
      
      #截取第6到第8个字符结果为log
      echo ${STR:5:3} 
      
      • 可用/src/target来将字符串中第一个src子串替换为target用//src/target可以将字符串中所有的src子串替换为target
      export STR='linux is not unix'
      
      echo ${STR/n/N} #输出liNux is not unix,替换第一个n
      echo ${STR//n/N} #输出liNux is Not uNix替换所有n
      
      • 字符串长度可用${#STR}来获取
      export STR=linux
      
      echo ${#STR} #输出结果为5
      
      
    3. 根据状态为字符串赋值

      • ${VAR-'value'}:如果当前VAR没有设置则返回value'值
      • ${VAR:-'value'}:如果当前VAR没有设置或为空串返回'value'值
      • ${VAR+'value'}:如果当前VAR没有设置返回空值否则返回'value'值
      • ${VAR='value'}:如果当前VAR没有设置将VAR设置为'value',并且返回'value'
      • ${VAR:='value'}:如果当前VAR没有设置或者为空串将VAR设置为'value',并且返回'value'
    4. 数组

      • 可以通过ele1 ele2 ele3 ...)来定义数组
      • 可以通过${ARR[i]}来访问数组中的元素
      • ${ARR[@]}或者${ARR[*]}可以返回数组中所有的元素
      • 获取数组中元素的个数可以使用如下表达式
        ${#ARR[@]}
        #注意,获取数组中元素数量必须用${#ARR[@]}而不是${#ARR}
        #在bash中${ARR}只会返回ARR数组的第一个元素
        #在bash中${#ARR}也只会返回数组中的第一个字符串的字符数量
        
      • 在bash中向数组中添加元素需要用如下方式
        ARR[${#ARR[@]}]=value
        
  • 整数运算

    • 在shell脚本中可以使用 var=$((expr)) 来执行浮点数运算和赋值但是在bash中expr仅支持整形的运算并不支持浮点数运算而zsh中expr既可以是整形也可以是浮点型运算
    #在bash中可以通过bc和管道来实现浮点数的运算
    #注意在使用bc命令执行浮点数运算时必须指定scale精度否则起默认情况下并不保留小数
    echo "scale=3;1.0/3" | bc
    
  • test命令和条件判断

    • test命令可以用于判断表达式为true/false
      1. 文件判断:
      • -e : 文件是否存在
      • -f : 文件是否存在且为普通文件
      • -d : 文件是否存在且为目录类型
      • -b : 文件是否存在且是块设备
      • -c : 文件是否存在且是字符型设备
      • -S : 文件爱呢是否存在且为sock
      • -p : 文件是否存在且为FIFOpipe
      • -L : 文件是否存在且为链接link
      1. 权限判断:
      • -r : 文件是否存在且对其有读权限
      • -w : 文件是否存在且对其有写权限
      • -x : 文件是否存在且对其有执行权限
      • -s : 文件是否非空白若为空文件返回为false
      1. 文件之间的比较:
      • f1 -ef f2 : 比较f1和f2两个文件是否是同一个文件
      • f1 -ot f2 : 比较f1文件的mtime是否比f2文件老
      • f1 -nt f2 : 比较f1的mtime是否比f2新
    • test命令用来比较整数浮点数无效
      • a -eq b : 比较a和b是否相等
      • a -ne b : 比较a和b是否不等
      • a -lt b : 比较a是否小于b
      • a -gt b : 比较a是否大于b
      • a -le b : 比较a是否小于等于b
      • a -ge b : 比较a是否大于等于b
    • test判断字符串
      • -n : 判断字符串是否不为空
      • -z : 判断字符串是否为空
      • == : 判断字符串是否相等
      • != : 判断字符串是否不相等
    • 多重条件判断
      • -a : and
      • -o : or
      • ! : not
    • 可以用[]来代替test命令例如 test a -eq b 可以被替换为[ a -eq b ],注意[ expr ]中'['和expr之间、expr和']'之间都需要有空格分隔
      • 通常在test或者[ expr]表达式中使用${VARNAME}时,都需要用" "将起扩起来,因为${VARNME}可能在字符串中包含空格,例如"touma kazua"若是不用”“将其包含那么起将被命令行识别为两个参数会导致too many arguments异常
  • shell传参

    • shell脚本可以在脚本名之后附加参数如 mysum.sh 1 2 ,其中 $0 为 mysum.sh ,$1 为1,$2 为2,以此类推。还有如下特殊参数:
      • $# : 除了脚本名称之外的参数个数
      • $@ : 除了脚本名之外其他参数组成的数组,各个变量仍然独立
      • $* : 除了脚本名之外所有参数聚合成的字符串,默认使用空格分隔
  • Shell条件判断

    • if-then结构
    if [ expr ];then
        some operations...
    fi
    
    • if-else-if结构
    if [ expr1 ];then
        some operations...
    elif [ expr2 ];then
        some operations...
    elif [ expr3 ];then
        some operations...
    else
        some operations...
    fi
    
    • switch-case结构
    case ${var} in
    "str1")
        some operations...
        ;;
    "str2")
        some operations...
        ;;
    "str3")
        some operations...
        ;;
    *)
        some operations...
        ;;
    esac
    
  • Shell函数

    • Shell函数可以通过function关键字来创建格式如下
    function FunctionName()
    {
        Function Body...
        #函数中也可以通过$1、$2来获取传递给函数的参数
    }
    
    #函数调用
    FunctionName arg1 arg2 ...
    #函数内通过$1只能读取传递给函数的参数变量而无法读取shell程序中的参数变量
    
  • Shell循环

    • while循环
    #while循环结构
    while [ expr]
    do
        some operations...
    done
    
    • until循环
    until [ expr ]
    do
        some operations...
    done
    
    • for-in循环
    #可以用seq命令指定首数/尾数/增量以便进行1n的遍历
    #seq 尾数
    #seq 首数 尾数
    #seq 首数 增量 尾数
    for var in obj1 obj2 obj3...
    do
        some operations...
    done
    
  • Shell语法检测

    • 可以使用sh -n来检测shell脚本的语法是否正确