Shell脚本中local赋值的陷阱

利用输出的文本内容进行判断(不好的示范)

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值