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

