跨SSH会话运行Expect脚本无法终止远程Java进程问题求助
问题原因分析与解决方案
核心问题
本地运行脚本正常,但远程ssh调用失败的根本原因是终端环境差异:
- 在server2本地运行脚本时,Expect处于交互式终端环境,PowerShell启动后会输出预期的
PS*>提示符,脚本能正常匹配并执行后续命令。 - 但从server1通过
ssh user@server2 './java_kill'调用时,server2上的Expect运行在非交互式无终端(non-interactive/non-tty)环境下,PowerShell启动后的输出行为发生了变化——它不会输出PS*>提示符,甚至可能没有任何标准输出,导致脚本里的expect "PS*> "匹配超时,后续的终止命令Get-Process Java | Stop-Process被发送到了未就绪的会话中,根本没被PowerShell接收执行。
从你提供的日志也能验证这一点:发送powershell.exe\r后,Expect的缓冲区是空的(does "" match glob pattern "PS*> "? no),说明没有收到PowerShell的预期输出,超时后直接发送了终止命令,自然无法生效。
可行解决方案
方案1:强制分配伪终端
从server1执行ssh命令时,添加-t参数强制为远程会话分配伪终端,让server2上的Expect运行在交互式环境下:
ssh -t user@server2 './java_kill'
这样PowerShell启动后会输出正常的PS*> 提示符,脚本就能按预期匹配执行。
方案2:简化脚本,直接远程执行命令
放弃交互式PowerShell会话,通过ssh直接传递PowerShell命令,彻底避免提示符匹配问题:
修改后的java_kill脚本:
#!/usr/bin/expect -f spawn ssh -l user server3 "powershell.exe -Command \"Get-Process Java | Stop-Process\"" expect "*passphrase*" send "passphrase\r" expect "*assword*" send "password\r" expect eof
这种方式更高效,也避免了终端环境带来的不确定性。
方案3:优化匹配逻辑(调试用)
如果必须保留交互式会话,可以先开启Expect的调试日志,查看PowerShell实际输出内容,再调整匹配规则:
在脚本开头添加exp_internal 1,这样会输出所有输入输出细节,帮助你确定PowerShell实际的输出内容,再修改expect的匹配模式(比如用更通用的*或者实际输出的提示符)。
内容的提问来源于stack exchange,提问作者thebananek
相关产品推荐
相关产品推荐

