使用Expect自动化SFTP文件传输失败,报错spawn id exp4未打开
问题分析与解决
你的Expect脚本出错的核心原因是spawn命令的使用方式完全错误,导致Expect无法正确跟踪sftp的交互会话,自然找不到对应的spawn id来发送密码。
错误根源拆解
你原来的脚本里写了:
expect -c 'spawn "put This_file_from_server_a.csv /TO/THIS/SERVER_B/PATH" | sftp remote@10.11.12.13; expect "assword:"; send "THE_PASSWORD\r"; interact'
这里有两个致命问题:
- spawn不能直接执行带管道的shell命令:Expect的
spawn是用来启动单个进程的,你把echo ... | sftp ...这种管道命令直接传给spawn,它会把整个字符串当作一个不存在的可执行文件路径。退一步说,就算用shell包裹执行管道,sftp请求密码时是从终端交互读取,而非标准输入——所以你通过管道传的put命令根本到不了sftp的交互阶段,sftp直接卡在密码输入,但Expect根本没在跟踪正确的sftp进程。 - 逻辑顺序错误:你应该先启动sftp进程,等它弹出密码提示后输入密码,进入sftp交互界面后再发送put命令,而不是一开始就把put命令通过管道传进去。
正确的Expect脚本写法
把逻辑调整为「启动sftp → 输入密码 → 发送put命令 → 退出会话」,脚本如下:
expect -c ' # 启动sftp进程,Expect会跟踪这个进程的输出 spawn sftp remote@10.11.12.13 # 等待密码提示(匹配"Password:"或"password:"的后半段,兼容大小写) expect "assword:" # 发送密码并回车 send "THE_PASSWORD\r" # 等待sftp进入交互模式的提示符 expect "sftp>" # 发送put传输命令 send "put This_file_from_server_a.csv /TO/THIS/SERVER_B/PATH\r" # 等待命令执行完成,再退出会话 expect "sftp>" send "exit\r" # 等待sftp进程完全结束,确保文件传输完成 wait '
额外优化提示
如果是第一次连接目标服务器,sftp会弹出指纹验证提示(比如Are you sure you want to continue connecting (yes/no)?),可以在脚本里增加这段处理逻辑:
expect -c ' spawn sftp remote@10.11.12.13 # 同时处理首次连接的指纹提示和后续的密码提示 expect { "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" exp_continue # 继续等待下一个提示(也就是密码提示) } "assword:" { send "THE_PASSWORD\r" } } expect "sftp>" send "put This_file_from_server_a.csv /TO/THIS/SERVER_B/PATH\r" expect "sftp>" send "exit\r" wait '
内容的提问来源于stack exchange,提问作者Omari Victor Omosa
相关产品推荐
相关产品推荐

