【Bash脚本】&符号引发source后变量取不到值

写在前面

  本文主要记录一下bash脚本中&符号导致source命令执行后,变量无法取到值的问题原因及解决方法。


目录

  • 写在前面
  • 一、场景描述
  • 二、具体步骤
    • 1.环境说明
    • 2.脚本
  • 写在后面


一、场景描述

  今天又是美好的一天,吃个早餐,改改代码,提测,打包、发版、测试,齐活,喝杯茶,下班。整套动作行云流水,相当丝滑,直到有一天,不那么顺畅,出问题了。

先说下这套组合拳中的发版原理,以下为简写版:
1、我们有一个 micro-config-server 的服务,配置文件为 application-template.yml

spring:
  datasource:
    url: ${databaseJdbcUrl}&useUnicode=true

2、项目 micro-config-server 下有一个启动jar的脚本,src/assembly/bin/bootstrap.sh
内容大致就是定义几个函数,例如start、stop、restart,然后以 nohoup 的方式启动

#!/bin/bash
source /opt/app/custom.sh
...
nohup $JAVACMD $JAVA_OPTS \
  -DdatabaseJdbcUrl="$databaseJdbcUrl" \
  -XX:+UseG1GC \
...

3、服务器上有一个自定义的文件 /opt/app/custom.sh

export databaseJdbcUrl=jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb

4、发版 micro-config-server 项目

交互流程:
(1)登录运维平台,发版,
首先会找到 micro-config-server 项目下 bootstrap.sh,执行start方法,启动jar

(2)执行 start 前,会通过 source 的方式将 custom.sh 导入到环境变量,
这样 bootstrap.sh 就能够拿到 databaseJdbcUrl 的值

(3)然后 bootstrap.sh 以 -D参数 的形式
把 customer.sh 的定义 databaseJdbcUrl 传递给 application-template.yml 中的$占位符,并进行赋值,
这样项目就能够跑起来了

说完了原理,简单说下背景情况:
事情是这样的,我们接了一个需求,做现有代码支持GaussDB数据库(原有DB是MySQL),这个需求由2个团队分别在2个分支上开发(甲做兼容改造、乙做功能开发)

甲团队先开发完,然后提测,在测试环境上一直运行着(此处有坑)。
乙团队新功能开发完毕,合并分支后,所有微服务要重新发版。

然而,悲剧发生了,
这个micro-config-server,总是找不到数据库连接地址,也就是databaseJdbcUrl 的值为空

起初以为是合并代码的问题,因为测试环境 micro-config-server 一直运行的好好的。但是,找到之前的安装包,手动执行 bootstrap.sh 脚本,依旧启动报错。奇了怪了,问题在哪里?

下面以一个实验说明,无法获取到 databaseJdbcUrl 的原因。


二、具体步骤

1.环境说明

名称 说明
CentOS Linux shell环境

2.脚本

[root@ecs-1678 ~]# vim custom.sh
// 内容如下
export databaseJdbcUrl1=jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb
export databaseJdbcUrl2=jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb&1=1
export databaseJdbcUrl3='jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb&1=1'

[root@ecs-1678 ~]# chmod 755 custom.sh

[root@ecs-1678 ~]# source custom.sh
-bash: 1=1: command not found
[1]+  Done export databaseJdbcUrl2=jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb

[root@ecs-1678 ~]# echo $databaseJdbcUrl1
jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb
[root@ecs-1678 ~]# echo $databaseJdbcUrl2

[root@ecs-1678 ~]# echo $databaseJdbcUrl3
jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb&1=1

有没有发现什么问题?
(1)databaseJdbcUrl2 没有输出值
(2)source custom.sh 之后出现了一行Done…

为什么没有值? 经过和之前环境上的脚本对比,发现这个bash脚本中多了一个&1=1

经查询资料,在Bash脚本中,&符号用于将命令放入后台执行。当在命令的结尾加上&符号时,该命令将在后台执行,不会阻塞当前Shell进程,而是会立即返回提示符,让用户可以继续输入其他命令。

此时基本上离真相很近了,问题找到,解决的办法也简单,给databaseJdbcUrl的值加上单引号。

// 修改前 export databaseJdbcUrl=jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb
// 修改后 export databaseJdbcUrl='jdbc:postgresql://localhost:8000/acs_db?currentSchema=acs_symstatdb'

联系到了小明,custom.sh这个配置文件确实被改动了,添加了1=1
重点来了,测试环境能够跑起来是因为小明在启动 micro-config-server 时,是以手工传参的方式执行了bootstrap.sh这个脚本把databaseJdbcUrl传了进去(类似于java -jar xxx.jar -DdatabaseJdbcUrl=…),而micro-config-server 自启动之后就再也没有重启过。

这乌龙搞得!所以修改公用通用的问题,一定要通知到相关项目组成员,进行方案评审。


写在后面

  如果本文内容对您有价值或者有启发的话,欢迎点赞、关注、评论和转发。您的反馈和陪伴将促进我们共同进步和成长。

你可能感兴趣的:(工作指北,bash,source)