# 变量的高级用法

# 变量的删除使用unset 变量

语法 说明
unset -v var 删除变量 var (默认,可以不加-v)
unset -f func 删除函数 func

# 变量替换和测试

语法 说明
${变量名#匹配规则} 从变量 开头 进行规则匹配,将符合 最短 匹配长度的数据进行删除
${变量名##匹配规则} 从变量 开头 进行规则匹配,将符合 最长 匹配长度的数据进行删除
${变量名%匹配规则} 从变量 尾部 进行规则匹配,将符合 最短 匹配长度的数据进行删除
${变量名%%匹配规则} 从变量 尾部 进行规则匹配,将符合 最长 匹配长度的数据进行删除
${变量名/旧字符串/新字符串} 变量内容符合旧字符串规则,则 第一个 旧字符串会被新字符串替代
${变量名//旧字符串/新字符串} 变量内容符合旧字符串规则,则 全部的 旧字符串会被新字符串替代
var="i love you,do you love me"

var1=${var#*ov}

echo $var1 # e you,do you love me

var2=${var##*ov}

echo $var2 # e me

var3=${var%ov*}

echo $var3 # i love you,do you l

var4=${var/e/E}

echo $var4 # i lovE you,do you love me

var5=${var//e/E}

echo $var5 # i lovE you,do you lovE mE

var6=${var/*ov/OV}

echo $var6 # OVe me

avatar

# 字符串处理

  • macOS 中 expr 的大批无法实现

# 计算字符串长度

方式 语法 说明
方式 1 ${#string} string 是变量
方式 2 expr length "$string" string 有空格,必须加双引号(该方法在 macOS 上不成功)
var="hello world"
len1=${#var}

echo $len1

# 获取字串(字符)在字符串中的索引位置

方式 语法 说明
方式 1 expr index $string substring 查找 substring 是按照 substring 里面的每一个字符在$string 里面去匹配的

# 获取字符串中字串的长度

方式 语法 说明
方式 1 expr match $string substr 必须从$string 头开始匹配

# 抽取字串

  • expr/从右开始匹配 下标从 1 开始计算,其余从 0 开始
方式 语法 说明
方式 1 ${string:position} 从 string 的 position 开始
方式 2 ${string:position:length} 从 string 的 position 开始,匹配长度为 length
方式 3 ${string: -position} 从 string 的 右边 开始匹配 -号前面有空格
方式 4 ${string:(position)} 从 string 的 左边 开始匹配
方式 5 expre substr $string $position $length 从 string 的 position 开始,匹配长度为 length
var1="kafka hadoop yarn mapreduce"

substr1=${var1:10}
substr2=${var1:10:6}
substr3=${var1: -5}
substr4=${var1: -10:4}

echo $substr1 # op yarn mapreduce
echo $substr2 # op yar
echo $substr3 # educe
echo $substr4 # map

# 练习

#!/bin/bash
#

string="Bigdata process framework is Hadoop,Hadoop is an open source project"

function print_tips() {
    echo "******************************"
    echo "(1) 打印string长度"
    echo "(2) 删除字符串中所有的Hadoop"
    echo "(3) 替换第一个Hadoop为Mapreduce"
    echo "(4) 替换全部Hadoop为Mapreduce"
    echo "******************************"
}

function len_of_string() {
    echo "${#string}"
}

function del_hadoop() {
    echo "${string//Hadoop/}"
}

function rep_hadoop_mapreduce_first() {
    echo "${string/Hadoop/Mapreduce}"
}

function rep_hadoop_mapreduce_all() {
    echo "${string//Hadoop/Mapreduce}"
}

while true; do
    echo "【string=$string】"
    print_tips
    read -p "Pls input your choice(1|2|3|4|q|Q): " choice

    case $choice in
    1)
        len_of_string
        break
        ;;
    2)
        del_hadoop
        break
        ;;
    3)
        rep_hadoop_mapreduce_first
        break
        ;;
    4)
        rep_hadoop_mapreduce_all
        break
        ;;
    q | Q)
        exit
        ;;
    *)
        echo "Error,input only in {1|2|3|4|q|Q}"
        ;;
    esac

done

# 命令替换

  • $(command) 表示命令替换 $(())主要用来进行整数运算,包括加减乘除,引用变量前面可以加$,也可以不加$

  • `和$()两者是等价的,但推荐初学者使用$(),易于掌握;缺点是极少数 UNIX 可能不支持,但`都是支持的

# 定义

某一段命令的结果作为另一个命令的一部分

# 语法

方式 语法
方式一 `command`
方式二 $(command)
echo "This is $(date +%Y) year"
echo "This is $(($(date +%Y) + 1)) year"

date +%j
echo "This year have passed $(date +%j) days"
echo "This year have passed $(($(date +%j) / 7)) weeks"

echo "There is $((365 - $(date +%j))) days before new year"
echo "There is $(((365 - $(date +%j)) / 7)) weeks before new year"
# 判定nginx进程是否存在,若不存在则自动拉起该进程
nginx_process_num=$(ps -ef | grep nginx | grep -v grep | wc -l)

if [ $nginx_process_num -eq 0 ]; then
    systemctl start nginx
fi

# 有类型变量

  • shell 本身是弱类型的,但是也可以申明类型,通过 declaretypeset 命令

# declear 参数命令表

参数 含义
-r 将变量设为只读
-i 将变量设为整数
-a 将变量定义为数组
-f 显示系统定义过的所有函数及内容
-F 仅显示系统定义过的函数名
-x 将变量声明为环境变量
  • 如果没有声明环境变量当前变量只对当前终端有效,声明成为环境变量在当前终端下的任意脚本里可以获取值,跨终端依旧不行
num1=2001
num2=$num1+1
echo $num2 # 2001+1

declare -i num2
num2=$num1+1
echo $num2 # 2002

# 取消声明变量

declare +r var
declare +i var
declare +a var
declare +x var

# 数组的基本操作

  • 不推荐在 shell 中频繁地使用数组

  • 数组下标从 0 开始

常用操作 操作命令
打印元素 echo ${array[2]}
打印所有元素 echo ${array[@]}
打印元素的个数 echo ${#array[@]} / ${#array[*]}
打印元素长度 echo ${#array[3]}
给元素赋值 array[3]="Li"
删除元素/数组 unset array[2](注意删除了之后数组内每个元素下标是不会变的)(Macos 无效);unset array
分片访问 echo ${array[@]:1:3}
元素内容替换 ${array[@]/e/E} 只替换第一个e;${array[@]//e/E} 替换所有的 e

# 数组的声明

  • 是以()包裹,每个下标用空格切分而不是逗号

array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")

declare -a array=("jones" "mike" "kobe" "jordan")

echo $array # jones

# 输出数组内容

echo ${array[@]}	# 输出全部内容
echo ${array[1]}	# 输出下标索引为1的内容

# 输出数组长度

echo ${#array[@]} # 数组内元素个数
echo ${#array[0]} # 数组内下标索引为0的元素长度

# 给数组某个下标赋值

array[0]="lily"				# 给数组下标索引为1的元素赋值为lily
array[20]="hanmeimei"		# 在数组尾部添加一个新元素

# 删除元素

unset array[2]		# 清除元素
unset array			# 清空整个数组

# 分片访问

${array[@]:1:3}		#  mike kobe jordan 显示数组下标索引从1开始到3的3个元素,不显示索引为4的元素
${array[@]:1}	 # 显示数组下标索引从1到最后

# 内容替换

${array[@]/an/AN}	# 将数组中所有元素内包含kobe的子串替换为mcgrady

${array[@]/e/E} # 将数组中所有元素第一个小写e变为大写E
${array[@]//e/E} # 将数组中所有元素全部小写e变为大写E


# 数组遍历

for v in ${array[@]}
do
    echo $v
done

# bash 数学运算之 expr

  • 只支持整数运算

  • 操作符之间要留空格

  • 该操作只能精确到整数,浮点数无效

  • 操作符很多设计关键字,需要转义\

expr $num1 + $num2 # 正确
expr $num1+$num2 # 错误

# 语法格式

方式 语法
方式 1 expr $num1 operator $num2
方式 2 $(($num1 operator $num2))
  • expr 直接在命令行中写会直接输出,而$(())的方式则需要赋值变量才行

  • $(())的方式语法不用那么严谨,变量不一定要加$,运算符余变量之间也可以没有空格。运算符也不需要转义

  • $(())的方式只能进行加减乘除商

# 操作符对照表

操作符 含义
num1 | num2 num1 不为空且非 0,返回 num1,否则返回 num2
num1 & num2 num1 不为空且非 0,返回 num1,否则返回 0
num1 < num2 num1 小于 num2,返回 1,否则返回 0
num1 <= num2 num1 小于等于 num2,返回 1,否则返回 0
num1 = num2 num1 等于 num2,返回 1,否则返回 0
num1 != num2 num1 不等于 num2,返回 1,否则返回 0
num1 > num2 num1 大于 num2,返回 1,否则返回 0
num1 >= num2 num1 大于等于 num2,返回 1,否则返回 0
num1 +-*%/ num2 num1 对 num2 求和差乘余商
num1=20
num2=100

expr $num1 \| $num2
expr $num1 \& $num2
expr $num1 \< $num2
expr $num1 \< $num2
expr $num1 \<= $num2
expr $num1 \> $num2
expr $num1 \>= $num2
expr $num1 = $num2
expr $num1 != $num2
expr $num1 + $num2
expr $num1 - $num2
expr $num1 \* $num2
expr $num1 / $num2
expr $num1 % $num2

# 练习

输入一个正整数,计算 1+2+..输入值的和,验证是否为正整数

  • tips: 判断一个树是否为正整数的方式为$num1 + 1,然后去echo $? 是否为 0
while true; do
    read -p "Pls enter a positive integer(num>0): " num

    expr $num + 1 &>/dev/null
    if [ $? -ne 0 ]; then # 注意这个条件要单独分离以防使用&&>0的时候导致报错
        echo "Error,You must input a interger"
        continue
    else
        if [ $(expr $num \> 0) -ne 1 ]; then
            echo "Error,You must input a postive integer"
            continue
        else
            sum=0
            for ((i = 0; i <= $num; i++)); do
                sum=$(expr $sum + $i) # 注意这里赋值要使用sum表示覆盖这个变量而不能使用$sum
            done
            echo "1+2+3+4+5+...+$num=$sum"
        fi
    fi
done

# bc

  • bc 是 bash 内置的运算器,支持浮点运算

# 操作符对照表

操作符 含义
num1 +-*%/ num2 num1 对 num2 求和差乘余商
num1 ^ num2 指数运算

# 进入 bc 界面使用

bc

23 / 5
4
23 % 5
3
scale=2 # 设置保留位数
23/5
4.60

# 在命令行或脚本中使用

echo "23/5" | bc # 4

echo "scale=4;23/5" | bc # 4.6000