bash 变量引用扩展

bash 变量引用扩展

我们都知道,在bash中,若定义了一个变量x=3,则使用${x}来进行变量替换 ,将x的值替换为3,在bash中,为变量替换提供了非常多的功能,下面我们一一来看下:

为不存在的变量赋默认值:

当引用一个不存在的变量的时候,默认会替换为空,比如,当没有定义x这个变量,直接使用它的时候,其结果会为空,案例如下:

bash 复制代码
#!/bin/bash

# 未定义变量x直接使用
echo x: ${x}

上述脚本执行的结果为:

bash 复制代码
# bash var_declaration.sh
x:
#

bash中,可以在变量后添加:=而后是该变量的默认值,这样的话,如果没有定义该变量,那么该变量的默认值则为新的值,比如:

bash 复制代码
#!/bin/bash

# 未定义变量x直接使用
echo x: ${x:=123}
echo x: ${x}

其执行结果为:

bash 复制代码
# bash var_declaration.sh
x: 123
x: 123
#

如上赋予默认值更多使用在接收命令行参数,用户可能并未输入参数,需要给定一个默认值的情况来执行,这样便可以直接进行if判断,而非提前判断是否为空了,脚本如下:

bash 复制代码
#!/bin/bash

operation=$1

echo 执行的选项为:${operation:=none}


if [ ${operation} = "yes" ];then
        echo "yes!!!"
fi

上述脚本,operation的值来源于命令行的第一个参数,如果并没有输入具体的参数,则使用默认值none,而后进行参数判断,如果假设没有给定默认值,那么在进行if字符串判断的时候,没有值和yes字符串做比对,会报错:[: =: unary operator expected

为不存在的变量赋临时值:

上述是为了不存在的变量给定了默认值,若在变量中添加-则表示赋予临时默认值,使用后即失效,例如:

bash 复制代码
#!/bin/bash

echo a: ${a:-5}
echo a: ${a}

上述脚本并没有定义变量a,但是在第一个echo语句的时候,将其变量替换为了5,此时并未重新定义a这个变量,所以第二个echo的时候,会输出为空,其结果为:

bash 复制代码
# bash var_declaration.sh
a: 5
a:
#

这种方式适用于仅判断一次的的脚本,比如,可以将上述脚本修改为这样的:

bash 复制代码
#!/bin/bash

operation=$1

if [ ${operation:-none} = "yes" ];then
        echo "yes!!!"
fi

这样,若operation为空的话,那么参数只在if判断中被赋予none的值,而后依然为空。

为不存在的变量抛错

在工具类脚本中,需要有非常强的健壮性,若某些关键配置缺失,需要报错并且退出脚本,以往我们的做法是直接进行判断,若不存在再exit非标准退出,比如下面这个脚本片段:

bash 复制代码
#!/bin/bash

# x未被定义

if [ -z ${x} ];then
        echo 错误:x未被定义
        exit 1
fi

上述脚本的含义为:若当x未被定义的时候,使用-z进行判断,-z的意思是后面待判断的值为空,则抛错,x未被定义,或者定义了为空,然后使用exit退出程序。

若要判断数十个或者数百个变量,即使使用函数的形式,也有大量的代码,其实在bash中,也为我们提供了类似的功能,比如下面语句可以完全代替上述语句块:

bash 复制代码
#!/bin/bash

# x未被定义
${x:?x未被定义或者为空}

echo "456"

直接使用:?关键字来判断,当x未被定义的时候,就对后面语句进行错误输出。且中断程序执行,直接退出,退出状态码为1。执行后结果为:

bash 复制代码
# bash var_declaration.sh
var_declaration.sh: line 4: x: x未被定义或者为空
# echo $?
1
#

上述结果,当判断x未被定义的时候,就进行预定义的错误输出,且退出程序,不会执行后续语句,最后的退出状态码为1。效果和上述使用if来判断一致(上述使用if判断是标准输出,这里是错误输出)。

字符串切片

bash中,可以对字符串进行切片处理,其用法为:

bash 复制代码
${待处理的字符串变量:偏移量[:长度]}

其中,长度部分是可选的;如果不写长度的话,则默认会截取到字符串的末尾。

当偏移量小于0的时候,默认会从第 0 位开始截取;若当长度为负数时,则表示从字符串末尾向前回退相应的字符数来进行截取。

这里需要注意的时,字符串起始是0,而非1

案例如下:

bash 复制代码
x="abcedf"

echo ${x:0}

上述代码表示x的值为abcedf,输出的时候,设置偏移量为0,长度没有写,则默认长度,所以最后输出的结果为:

bash 复制代码
abcedf

若想截图3个字符,则只需将长度设置为3即可:

bash 复制代码
x="abcedf"

echo ${x:0:3}

上述代码的结果为:

bash 复制代码
abc

从想直接截取到最后的2个字符前,只需要将长度设置为-2即可,例如:

bash 复制代码
x="abcedf"

echo ${x:0:-2}

其结果为:

bash 复制代码
abce

若调整了偏移量,假设为2,则表示从第二位开始截取,截取的长度由后面的参数来决定,比如:

bash 复制代码
x="abcedf"

echo ${x:1:3}

上面代码表示从字符串的第1位开始截取,截取的长度为3

字符串匹配删除

bash中,不仅可以对字符串进行切片,还能进行匹配删除,匹配可以分为惰性匹配和贪婪匹配,当然在bash中称为是最短匹配最长匹配

字符串匹配删除的语法为:

bash 复制代码
${待处理的字符串变量#最短删除规则}
${待处理的字符串变量##最长删除规则}

这里所指的规则可以是普通字符串,也可以是匹配模式。这个匹配模式,不同于正则表达式,这里暂时不做讲述。回到字符串匹配删除这里来。

比如有如下字符串:

bash 复制代码
x=dabcabcabcef

比如想要删除abc,可以这样使用:

bash 复制代码
x=dabcabcabcef

echo ${x#*abc}
echo ${x##*abc}

上述删除规则为*abc,其中*表示匹配任意个字符,对于字符串dabcabcabcef而言,*abc可以匹配为abc字符串本身,也可以匹配为dabc,也可以匹配为dabcabcabc,只要是出现abc的,前面都可以被匹配到。

所以最短匹配删除的语句是${x#*abc},对于dabcabcabcef字符串而言,*abc表示从开头开始,匹配到第一个出现的abc字符串,即:dabc

而对于最长匹配删除的语句是${x##*abc},对于字符串dabcabcabcef而言,*abc表示从开头开始,匹配到最后一个abc字符串,即:dabcabcabc

所以,该脚本执行的结果为:

bash 复制代码
# bash var_declaration.sh
abcabcef
ef
#

总结

bash中,已经为我们提供了变量提供了很多的操作,包括判断变量是否已经赋值,为不存在的变量抛错等,提供了字符串切片,匹配删除等,无需自己亲自动手实现,只需要调用语法,便可以轻松完成这些步骤,当然bash变量引用扩展还不止如此,由于篇幅有限,就介绍到这里,剩下的后面有机会再详细介绍。

相关推荐
Sheep Shaun10 小时前
如何让一个进程诞生、工作、终止并等待回收?——探索Linux进程控制与Shell的诞生
linux·服务器·数据结构·c++·算法·shell·进程控制
dingdingfish1 天前
Bash 学习 - 第1章:Introduction
bash·shell·programming·introduction
pr_note3 天前
legality检查
shell·tcl
啥都不懂的小小白4 天前
Shell脚本编程入门:从零基础到实战掌握
前端·shell
dingdingfish8 天前
GNU Parallel 学习 - 第1章:How to read this book
bash·shell·gnu·parallel
似霰11 天前
Linux Shell 脚本编程——核心基础语法
linux·shell
似霰11 天前
Linux Shell 脚本编程——脚本自动化基础
linux·自动化·shell
偷学技术的梁胖胖yo13 天前
Shell脚本中连接数据库查询数据报错 “No such file or directory“以及函数传参数组
linux·mysql·shell
纵有疾風起21 天前
【Linux 系统开发】基础开发工具详解:软件包管理器、编辑器。编译器开发实战
linux·服务器·开发语言·经验分享·bash·shell
gis分享者23 天前
Shell 脚本中如何使用 here document 实现多行文本输入? (中等)
shell·脚本·document·多行·文本输入·here