shell高级编程

shell高级编程

shell高级编程

本文主要涵盖函数、case、数组、字符串、信号捕捉、ACSII颜色等,下面让我们开始吧

1. 函数

函数是结构化编程的一个重要特性,主要可以实现代码的复用,使得代码更加整洁,可用性更好。下面让我们来看一下函数的定义与使用

# bash函数定义支持一下两种方式
function f_name {
	#函数体
	[return]
}
f_name() {
	#函数体
	[return]
}

# return 只能是0-256中间的值,返回值保存到$?中

# 函数的调用方式
f_name arg1 arg2 ...

# 函数可以使用局部变量,当函数执行完毕后,变量会被释放
local VAR

# 函数内参数接收参数$1,$2 其他同shell 如 $*(所有参数同$@) $#(个数)等
declare -f 可以显示定义函数的清单
declare -F 可以只显示定义的函数名
unset -f 函数名 从shell内存中删除函数
export -f 函数名 将函数输出给shell

# 示例代码
#!/bin/bash

function abc {
    RESULT=`expr $1 \% 2`
    if [ $RESULT -eq 0 ];then
        return 0
    else
        return 1
    fi
}

echo "请给定一个数字,判断是否能被2整除"
read num
abc $num
case $? in
    0)
        echo "yes"
        ;;
    1)
        echo "no"
        ;;
    *)
        echo "error"
        ;;
esac

2. CASE语句

当代码有多个分支需要判断时,这是使用if-elif-else会比较臃肿,这时就可以使用case语句

case $var in
pat1)
	分支1
	;;
pat2)
	分支2
	;;
*)
	分支n
	;;
esac

# PATTERN支持GLOB统配和|
# *) 相当于其他语言的default
# ;; 相当于break

3. 数组

数组是存储多个元素的连续空间,包含数组名和数组索引,编号从0开始,另外bash4版本之上的,支持关联数组,键值对的形式,类似hash

# 声明数组
declare -a Name 声明索引数组
declare -A Name 声明关联数组
# 赋值方式
 1.给指定的索引赋值		ARRAY[index]=value
 2.一次赋值全部		ARRAY=('val1' 'val2' ...)
 3.只赋值给特定的索引,bash支持稀疏格式数组  ARRAy=([0]='val1',[3]='val4')
 4.读取用户的输入 read -a ARRAY_NAME
# 引用数组
${ARRAY[INDEX]}
注意:引用时,只给数组名,表示引用下标为0的元素
${#ARRAY_NAME[*]} ${#ARRAY_NAME[@]} 获取数组长度
${ARRAY_NAME[*]} ${ARRAY_NAME[@]} 表示获取数组所有元素
# 数组元素切片
${ARRAY_NAME[@]:offset:number} offset:表示偏移过的元素;number:要取出的元素个数;省略number时,表示取偏移量之后的所有元素
# 非稀疏格式数组追加元素
ARRAY_NAME[${#ARRAY_NAME[*]}]='val'
# 删除数组指定元素
unset ARRAY[INDEX]
# 关联数组
declare -A ARRAY_NAME
ARRAY_NAME=([key1]='val1' [key2]='val2'...)
# 示例代码
# 定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的文件;统计其下标为偶数的文件中的行数之和
#!/bin/bash

declare -a logfiles
logfiles=(/var/log/*.log)
declare -i lines=0

for i in $(seq 0 $[${#logfiles[*]}-1]);do
    if [ $[i%2] -eq 0 ];then
        let lines+=$(wc -l ${logfiles[$i]} | cut -d' ' -f1)
    fi
done

echo "Lines:${lines}."

4. 字符串

bash内置了强大的字符串处理功能,在功能没有说明会操作原变量的情况下,默认是不会操作原变量,可以使用新的变量进行接收返回值

# 字符串切片
${var:offset:number}
取字符串的子串
取字符串的最右侧的几个字符:${var: -length} 冒号后必须有一个空白字符
# 基于模式取子串
${var#*word} 其中word是指定的分隔符;功能:自左到右,查找var第一次出现分隔符,删除字符串开头到次分隔符之间的所有字符包含分隔符
${var##*word} 其中word是指定的分隔符;功能:自左到右,查找var最后一次出现分隔符,删除字符串开头到次分隔符之间的所有字符包含分隔符
${var%word*} 其中word是指定的分隔符;功能:自右到左,查找var第一次出现分隔符,删除此分隔符到字符串尾部的所有字符
${var%%word*} 其中word是指定的分隔符;功能:自右到左,查找var最后一次出现分隔符,删除此分隔符到字符串尾部的所有字符
# 查找替换
${var/PAT1/SUB1} 查找var中第一次被PAT匹配的字符串并将其替换为SUB
${var//PAT1/SUB1} 查找var中所有被PAT匹配的字符串并将其替换为SUB
${var/#PAT1/SUB1} 查找var中行首被PAT匹配的字符串并将其替换为SUB
${var/%PAT1/SUB1} 查找var中行尾被PAT匹配的字符串并将其替换为SUB
注意:PAT使用glob风格通配符
# 查找删除,其实就是替换为空
${var/PAT1} 
${var//PAT1}
${var/#PAT1}
${var/%PAT1}
# 字符大小转换
${var^^}  所有的小写转大写
${var,,}  所有的大写转小写
# 变量赋值
${var:-val} 如果var变量为空或未设置,则返回val,否则返回var的值
${var:=val} 如果var变量为空或未设置,则返回val并将val赋值给var,否则返回var的值
${var:+val} 如果var变量不为空,则返回val
${var:?ERROR_INFO} 如果var为空或未设置,则输出ERROR_INFO信息,错误输出流,stderr

# 示例代码
#!/bin/bash

# 获取用户输入
read_name() {
    read -p "请输入一个可执行程序名称,输入quit退出: " name
    [[ $name == 'quit' ]] && exit 0 || cp_cmd $name
}
# 拷贝命令函数
cp_cmd() {
    local cmd=$1
    if `which $cmd &> /dev/null`;then
        echo "开始复制命令程序:${cmd}..."
        local cmd_path=$(which $cmd)
        local cmd_dir=$(dirname ${cmd_path})
        test -d /mnt/sysroot/${cmd_dir} || mkdir -p /mnt/sysroot/${cmd_dir}
        cp -f ${cmd_path} /mnt/sysroot/${cmd_path}
        declare -a ldd_files
        ldd_files=($(ldd ${cmd_path}))
        for file in ${ldd_files[*]};do
            local ldd_dir=$(dirname $file)
            test -d ${ldd_dir} && mkdir -p /mnt/sysroot/${ldd_dir} &> /dev/null
            test -f $file && cp -f $file /mnt/sysroot/$file
        done
        echo "${cmd}命令复制完成"
        read_name
    else
        echo "获取程序路径失败"
        read_name
    fi
}

read_name

5. 信号捕捉

trap命令是shell的内建命令,用于在脚本中指定如何处理对应的信号,比如说,通常脚本接收到系统SIGINT信号时,通常时退出进程,但是我们可以使用trap命令指定当脚本接收到SIGINT信号时的动作,而不是单纯退出

#一般常用于捕捉 HUP和INT(中断)信号,无法捕捉9和15信号
trap "mytrap" INT

mytrap(){
  echo "QUIT"
  exit 1
}

6. 颜色使用

bash支持使用acsii颜色,格式如下:

\033[31m hello \033[0m
##m
左侧#:
	3 前景色
	4 背景色
右侧#:颜色种类,支持1-7
#m: 加粗,闪烁等功能

#示例代码:
echo -e '\033[32m hello \033[0m'
#可以使用分号分割组合使用,如下:
echo -e "\033[41;32;5m hello \033[0m"

image-20200507093423292