Expect 5.45脚本:如何获取send命令的远程执行返回值
解决Expect脚本远程执行命令只返回纯净结果的问题
我太懂你的困扰了——写的Expect远程脚本总是输出一堆乱七八糟的交互信息,而你只想拿到命令执行的干净结果对吧?咱们直接动手改脚本,把冗余信息全部过滤掉。
原脚本的核心问题
你的脚本现在用interact把终端控制权交还给用户,而且没有对ssh登录欢迎信息、输入的命令本身、提示符这些内容做过滤。要拿到纯净的命令输出,我们需要调整这几个关键环节:
- 关闭默认的全局交互日志,避免打印所有会话过程
- 精准匹配远程服务器的提示符,防止误捕获无关内容
- 专门捕获命令执行后的输出,剥离冗余部分
- 用正常的会话结束逻辑替换
interact
修改后的完整脚本
#!/usr/bin/expect #usage: no_interact_cmd.sh ip_address username password command set ip_address [lindex $argv 0] set username [lindex $argv 1] set password [lindex $argv 2] set command [lindex $argv 3] # 关闭默认交互日志,只保留我们主动捕获的内容 log_user 0 spawn ssh ${username}@${ip_address} expect { "*password:" { send "${password}\n" } # 处理首次连接的主机密钥确认(可选,根据你的场景调整) "*Are you sure you want to continue connecting (yes/no)?" { send "yes\n" expect "*password:" send "${password}\n" } } # 匹配登录后的提示符:兼容root的#和普通用户的$,可根据实际格式调整 expect -re {\$|#} # 发送要执行的命令 send "${command}\n" # 捕获命令执行结果:匹配从命令输出结束到下一个提示符之间的内容 expect -re "(.*)\n(\$|#)" set clean_output $expect_out(1,string) # 退出远程会话 send "exit\n" expect eof # 打印最终的纯净结果 puts $clean_output
关键修改点说明
log_user 0:直接关闭Expect默认的全量交互日志输出,避免打印spawn、send、expect的所有过程信息。- 灵活的提示符匹配:用正则
-re {\$|#}适配大部分服务器的提示符(root用#,普通用户用$),如果你的服务器提示符是[user@host ~]#这种格式,可以改成-re "\[.*\] (\$|#)"。 - 精准捕获输出:通过
expect -re "(.*)\n(\$|#)"把命令执行后到下一个提示符前的所有内容存到clean_output变量里,这就是我们要的纯净结果。 - 替换
interact为expect eof:interact会把终端控制权交回用户,而expect eof会等待ssh会话正常结束,避免脚本提前退出。 - 新增主机密钥处理:首次连接新服务器时会弹出密钥确认提示,脚本里加了这个分支,防止脚本卡住。
测试执行
用你原来的命令测试:
./no_interact_cmd.sh 192.?.?.? root *** 'hostname'
现在应该只会输出目标主机的hostname,再也看不到那些冗余的交互信息了。
额外提示
如果你的命令执行时间较长,可以给expect加上超时参数,比如expect -timeout 30 -re "(.*)\n(\$|#)",避免脚本无限等待。
内容的提问来源于stack exchange,提问作者liuchu
相关产品推荐
相关产品推荐

