利用输出的文本内容进行判断(不好的示范)
release_string=$(timeout 20 /bin/rpm -q euleros-release 2>/dev/null)
如此获取系统版本信息,是不是完美了呢?既可以将正常回显封装到release_string变量,又可以将异常信息扔给/dev/null。
如果不确定,咱们执行试试好了:
~]# release_string=$(timeout 20 /bin/rpm -q euleros-release 2>/dev/null)
~]# echo "$release_string"
package euleros-release is not installed
不完美了,not installed信息竟然不是stderr。通过| grep -v 呢?
release_string=$(timeout 20 /bin/rpm -q euleros-release 2>/dev/null |grep -Ev 'not installed|未安装')
如上代码,同时考虑了英文和中文回显,“完美”!!!
真的完美了吗?NO!
我们下发的shell脚本的编码是UTF-8,有些机器上的中文编码可能是GBK或者其他,会乱码的哦~~
所以呢?最好的方法是通过状态码判断是否安装,这样代码更加健壮。如何做呢?
利用状态码进行判断(最佳实践)
local release_string=$(timeout 20 /bin/rpm -q FusionOS-release 2>/dev/null)
[ $? -ne 0 ] && unset release_string
看着不错,应该能解决问题了。
然并卵啊,执行后你会发现这里的$?会一直是0,不管rpm -q 查询的软件包安装没安装。其实呢,到这里,才是我真正想表达的。那就是local声明变量操作。
local赋值的陷阱
核心问题在于:$? 是一个动态值,它总是保存上一条命令的退出状态,然而并不是一行代码会被判定为上一条命令。
local var=""
其实是两个操作:声明&赋值,并且声明的执行顺序总在最后。 我们来做个实验来了解一下local var声明变量。
test_case() {
# 测试1:local 声明并赋值,观察 $?
# false命令的退出码是1
local test_var=$(false)
echo "local赋值后的\$?是: $?" # 输出 0,因为local命令成功了
# 测试2:纯赋值,观察 $?
unset test_var
test_var=$(false)
echo "纯赋值后的\$?是: $?" # 输出 1,反映了false命令的失败
# 测试3:直接测试local命令
local another_var
echo "纯local声明后的\$?是: $?" # 输出 0,因为声明成功
}
test_case
~]# test_case
local赋值后的$?是: 0 # 输出 0,因为local命令成功了
纯赋值后的$?是: 1 # 输出 1,反映了false命令的失败
纯local声明后的$?是: 0 # 输出 0,因为声明成功
最后的代码
为了确保你的脚本能准确捕获关键命令的退出状态,请遵循以下原则:
原则:将“变量声明”与“关键操作的执行和状态捕获”分离。
local release_string
release_string=$(timeout 20 /bin/rpm -q FusionOS-release 2>/dev/null)
[ $? -ne 0 ] && unset release_string

1672

被折叠的 条评论
为什么被折叠?



