You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expect命令被上层shell脚本调用时执行输出无法正常写入文件问题

问题根因

  1. 命令执行顺序错误:原脚本中expect eof放在了send -- "exit\r"前面,逻辑上是先等待sftp进程主动结束再发退出命令,完全颠倒了执行顺序。非交互式运行(被上层脚本调用)时,sftp进程不会主动退出,会一直挂起直到超时,此时输出还驻留在缓冲区没有刷新到标准输出,自然无法写入目标文件。
  2. 输出匹配逻辑不完善:仅用expect -re "(.*)\r"仅匹配了第一行输出的回车,单文件场景下输出只有1行文件信息+后续的sftp提示符,只抓取第一行后没有等待所有输出落盘。且非交互式场景下标准输出默认是全缓冲模式,只有缓冲区满、主动刷新、进程正常退出时才会写出内容,多文件场景下输出内容多刚好填满缓冲区所以能正常写出,单文件内容少缓冲没满就被异常终止所以没有内容。
  3. 硬等待不可靠:sleep 5的固定等待逻辑无法适配不同网络环境下的命令执行速度,容易出现输出还没返回就进入后续流程的问题。

修复后的sftp_pass.sh脚本

log_user 0
##-------------Start of script----------------
set expectedcmd [lindex $argv 0]
set port [lindex $argv 1]
set user [lindex $argv 2]
set host [lindex $argv 3]
set pass [lindex $argv 4]

if {$expectedcmd=="list"} {
    set file [lindex $argv 5]
    spawn sftp -oPort=$port $user@$host
    expect "password:"
    send "$pass\n"
    set prompt "sftp>";
    set command "ls -l $file";
}
##---------------------------------
expect "$prompt"    ;# wait for prompt
send   "$command\r" ;# send command
expect "$command\r" ;# discard command echo
log_user 1
# 匹配所有ls输出直到出现sftp提示符,确保拿到全量结果
expect -re "(.*)$prompt"
# 主动输出匹配到的内容,强制刷新缓冲区
puts $expect_out(1,string)
# 先发送退出命令,再等待进程正常结束
send -- "exit\r"
expect eof
##-------------End of script--------------------

额外验证点

  • 确认/temp目录存在且运行脚本的用户有写入权限,避免无权限导致的空文件问题
  • 上层脚本调用时如果用了后台运行逻辑,确认没有把标准输出重定向到其他位置
  • 生产环境不建议使用明文密码做认证,推荐改用ssh密钥方案替代expect传密码的实现

内容的提问来源于stack exchange,提问作者djgcp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.17 17:54:08