含Expect的Bash脚本执行SSH调用时出现引号错误排查
引号解析冲突导致的Expect脚本SSH报错排查
核心原因:Expect与Bash的引号处理逻辑不一致
- 手动执行
ssh -t anon@machine 'bash -c "cd /tmp;"'时,本地Bash会优先解析外层单引号:单引号会屏蔽内部所有特殊字符(包括双引号),最终传给SSH的命令是bash -c "cd /tmp;",远程Bash能正确识别嵌套引号并执行。 - 但在你的Expect脚本中,
ssh_param定义为"-t ${scp_user}${_machine} 'bash -c \"cd /tmp;\"'"时,问题出在:- Expect不识别Bash的单引号语法,外层单引号在Expect里只是普通字符,不会起到“保护内部字符串”的作用。
- Expect会先解析转义的双引号
\",最终传给SSH的命令包含了多余的单引号,变成'bash -c "cd /tmp;"'。远程Shell解析时,会把外层单引号当作命令的一部分,导致引号匹配混乱,触发extra characters after close-quote错误。
可行的修正方案
方案1:适配Expect的转义规则,去掉外层单引号
直接用转义双引号包裹bash -c的参数,避免嵌套单引号带来的解析冲突:
ssh_param="-t ${scp_user}${_machine} bash -c \"cd /tmp;\""
方案2:用Expect大括号保护复杂命令
如果需要执行包含环境变量的多段命令,用Expect的{}大括号包裹整段远程命令,避免频繁转义:
set ssh_param "-t ${scp_user}${_machine} {bash -c \"cd /tmp; export TEST_VAR=foo; echo \$TEST_VAR\"}"
注意:大括号内部的变量引用(比如$TEST_VAR)需要加反斜杠转义,防止被本地Expect提前解析。
为什么去掉bash -c后能正常运行
当你改成"-t ${scp_user}${_machine} \"cd /tmp;\""时,传给SSH的命令是单纯的cd /tmp;,没有嵌套的引号结构,远程Shell不需要处理复杂的引号解析,因此可以正常执行。
内容的提问来源于stack exchange,提问作者gunnersFc
相关产品推荐
相关产品推荐

