为何export命令在跨SSH传递环境变量时表现不同?
先明确场景:Main服务器上已执行export CI="CD",通过SSH调用Secondary服务器的命令,两种不同写法导致script.sh输出结果截然不同。
核心原因拆解
1. 本地shell的变量预替换
你用双引号包裹SSH命令时,Main服务器的shell会先把命令里所有$开头的变量替换成本地值,再把替换后的完整命令发送给Secondary服务器执行。
第一个命令里的
export CI=$CI:
Main的shell会把后面的$CI替换成本地的"CD",传到Secondary的实际命令是export CI=CD。这一步直接在Secondary的shell会话里定义了CI变量,同时通过export标记为环境变量,后续的./script.sh作为该shell的子进程,会自动继承这个环境变量,因此能输出"CD"。第二个命令里的
export CI;:
这里的CI是变量名,没有赋值操作。传到Secondary的命令就是export CI,但此时Secondary的shell里根本不存在CI变量——之前的echo $CI > file只是把本地替换后的"CD"写入文件,并没有在Secondary的shell环境里定义CI。export一个不存在的变量是无效操作,相当于没做任何事,所以./script.sh运行时环境里没有CI,自然输出空行。
2. export命令的本质
export的作用是将已存在的shell变量标记为环境变量,让子进程可以继承它——但前提是这个变量已经被定义过。它本身不能凭空创造变量,必须先完成变量赋值,再用export导出(或者像第一个命令那样,赋值和导出一步完成)。
验证与修正
如果想让第二个命令生效,需要先在Secondary的shell里定义CI变量,再导出:
export CI="CD" && ssh Secondary "CI='$CI'; export CI; ./script.sh"
也可以用单引号包裹SSH命令避免本地预替换,或者通过SSH的SendEnv参数传递环境变量(前提是Secondary的sshd配置允许接收该变量)。
内容的提问来源于stack exchange,提问作者Ivan

