使用Ruby实现FTP交互时脚本无法读取输出且挂起的问题排查
解决Ruby脚本调用FTP时无法读取输出、发送命令后挂起的问题
问题根源
- FTP交互时序错误:脚本批量发送所有命令,但FTP是交互式程序,必须等待它返回
ftp>提示符后才能发送下一个命令,直接批量发送会导致命令在FTP未就绪时被提交,引发阻塞。 - 输出缓冲机制问题:FTP默认可能使用全缓冲而非行缓冲,导致
stdout.each无法及时捕获输出,读取线程一直处于等待状态。 - 缺少响应同步逻辑:没有等待单条命令的响应完成就发送下一条,导致交互流程混乱。
修正后的脚本
require 'open3' # 定义要发送的FTP命令 commands = [ 'ascii', 'quote site filetype=jes', 'put amblist.jcl', 'dir', 'quit' # 必须添加退出命令,避免FTP进程残留 ] user_id = 'mikes01'.downcase # 加入-inv参数:-n禁止自动登录,-i关闭交互确认,-v开启 verbose模式输出所有响应 program_command = "ftp -inv ftp://#{user_id}:mypwd@bigiron" captured_results = [] pattern = /你的目标匹配正则/ # 替换为你需要捕获的特定格式正则表达式 Open3.popen2e(program_command) do |stdin, stdout_err, wait_thread| # 后台线程读取并处理FTP输出,捕获匹配结果 reader_thread = Thread.new do stdout_err.each_line do |line| puts line.chomp # 实时打印FTP响应 # 扫描并保存匹配内容 matches = line.scan(pattern) captured_results.concat(matches) unless matches.empty? end end # 等待FTP初始化完成,直到出现ftp>提示符 loop do line = stdout_err.readline puts line.chomp break if line.include?('ftp>') end # 逐个发送命令,确保每条命令执行完成后再发下一条 commands.each do |cmd| puts ">>> 发送命令: #{cmd}" stdin.puts cmd stdin.flush # 强制刷新输入缓冲区,确保命令立即发送 # 等待当前命令执行完成,直到再次出现ftp>提示符 loop do line = stdout_err.readline puts line.chomp break if line.include?('ftp>') end end stdin.close reader_thread.join # 等待读取线程处理完所有输出 wait_thread.value # 获取FTP进程的退出状态 end # 对捕获的结果进行后续计算或处理 puts "\n捕获到的匹配结果:" p captured_results # 在这里添加你的计算逻辑
关键改动说明
- FTP参数优化:
-inv参数解决自动登录冲突、交互阻塞问题,同时确保所有响应都能被捕获 - 合并输出流:用
popen2e替代popen2,将标准输出和错误输出合并,避免遗漏关键反馈 - 时序同步:通过等待
ftp>提示符,确保FTP在就绪状态下接收命令,避免提前发送导致的阻塞 - 显式刷新缓冲区:
stdin.flush确保命令立即发送到FTP进程,不会因缓冲延迟发送 - 强制退出逻辑:添加
quit命令,确保FTP执行完所有操作后正常退出,避免进程残留
内容的提问来源于stack exchange,提问作者Mike Slinn
相关产品推荐
相关产品推荐

