为何在eval中需为$?添加转义字符?bash技术咨询
为什么
eval中$?需要转义而$A不需要? 这本质是bash变量展开时机的问题,咱们一步步拆解来搞明白:
1. 先看你第一个失败的命令
执行这段代码时:
export A=1 eval "echo $A; echo $A; lll; echo $?"
bash的处理流程分两步:
- 第一步:外层shell先解析双引号里的内容,做变量替换:
$A会直接替换成你提前export的1,这正是你想要的效果;$?是bash里记录「上一个执行命令退出码」的特殊变量,此时上一个命令是export A=1(执行成功,退出码为0),所以$?直接被替换成0。
- 第二步:把替换后的字符串交给
eval执行,此时eval拿到的命令是:
所以最后输出的echo 1; echo 1; lll; echo 00是export命令的退出码,根本不是lll的——因为$?在eval执行前就被外层shell替换完了!
2. 为什么给$?加\就有效?
当你写成:
eval "echo $A; echo $A; lll; echo \$?"
外层shell解析双引号时,\$会被处理成保留$符号(转义的作用就是让bash把$当作普通字符,不做变量替换),所以替换后的字符串交给eval时是:
echo 1; echo 1; lll; echo $?
这时候eval执行到echo $?时,$?才会被替换成它前面的lll命令的退出码(127,对应「命令未找到」的错误),这就得到了你想要的结果。
3. 为什么$A不需要转义?
因为你希望$A的值在eval执行前就确定下来(用外层shell中已经export的A=1),外层shell直接把$A替换成1,eval拿到的就是echo 1,完全符合预期。
当然你也可以给$A加转义写成\$A,这时候外层shell会保留$A,交给eval时再由eval去替换$A的值——因为A是全局export的变量,所以结果也是1,这两种写法效果一致,但背后的变量替换时机不同:
- 不加转义:外层shell完成
$A的替换 - 加转义:
eval内部的shell完成$A的替换
内容的提问来源于stack exchange,提问作者atline
相关产品推荐
相关产品推荐

