Bash中一行式命令替换赋值变量后立即使用失效的原因及一行式传递GPG解密密码给Ansible的解决方案
Bash中一行式命令替换赋值变量后立即使用失效的原因及一行式传递GPG解密密码给Ansible的解决方案
嘿,我来给你拆解下这个问题,你遇到的情况其实是Bash环境变量作用范围的典型坑!
一、为什么你的TEST一行式会输出空?
先看你写的这条命令:
echo "Hello world!" > test.txt && TEST="$(cat test.txt)" echo "$TEST"
问题出在Bash对VAR=value command这种写法的处理逻辑上:
- 当你在命令前加变量赋值时,这个赋值只对紧跟的command进程的临时环境生效,不会影响当前Shell的变量;
- 而你命令里的
echo "$TEST",其中的$TEST是在当前Shell里先解析的——这时候TEST还是你之前设的空字符串,解析完成后才会执行TEST="$(cat test.txt)" echo ...这一步,而此时临时赋值的TEST只存在于echo子进程的环境中,但echo已经拿到了之前解析好的空值,自然输出空白。
反观你分开写的版本,TEST=$(cat test.txt)是在当前Shell里完成赋值,之后的echo "$TEST"自然能读到正确的值。
二、怎么让TEST的一行式正常工作?
如果你非要写成一行,有两种常用方法:
方法1:用子shell包裹命令组
把赋值和echo放在同一个子shell里,这样变量在子shell的环境里生效:
echo "Hello world!" > test.txt && (TEST="$(cat test.txt)"; echo "$TEST")
方法2:用大括号创建当前Shell的命令组
大括号不会创建子shell,变量会留在当前Shell里(注意大括号前后的空格和分号不能少):
echo "Hello world!" > test.txt && { TEST="$(cat test.txt)"; echo "$TEST"; }
三、你的Ansible场景正确写法是什么?
回到你实际要解决的问题:把GPG解密的密码传给ansible-playbook。其实你写的这条命令是完全正确的!
ANSIBLE_VAULT_PASSWORD="$(gpg -d ~/gpg_encrypted_vault_password_file 2>/dev/null)" ansible-playbook etc etc etc
因为这里的ANSIBLE_VAULT_PASSWORD=xxx是直接把变量注入到ansible-playbook进程的环境中,Ansible会读取这个环境变量作为Vault密码,完全符合你的需求——和TEST的场景不同,这里你不需要在当前Shell里使用这个变量,只需要让子进程(ansible-playbook)拿到它,所以这种写法是正确的,放心用就行。
顺便说一句,我完全理解你不想明文存Vault密码的心情,用GPG加密+代理的方式确实是更安全的方案!
备注:内容来源于stack exchange,提问作者Rob
相关产品推荐
相关产品推荐

