如何通过get请求显示popen输出?

时间:2014-07-29 19:30:11

标签: javascript ruby shell unix sinatra

我有一些Ruby脚本用于自动执行一些可能需要很长时间才能完成的rsync任务。我使用popen来运行命令:

def process(command)
  io = IO.popen(command) 
  output = io.read
  io.close 
  return output 
end

该命令由Sinatra app中的get请求执行:

get '/sync' do
  stream do |out|
    rsync_command = "rsync somedir" 
    out << process(rsync_command)
  end
end

然后我在前端使用Ajax请求访问输出:

$.get('/sync', function (data) {
 console.log(data);
});

是否可以显示shell输出,而不是仅在过程结束时返回?

2 个答案:

答案 0 :(得分:0)

  

IO :: POPEN:

     

将指定的命令作为子进程运行;子流程的标准   输入和输出将连接到返回的IO对象。

stdout是一个文件。你告诉ruby用行io.read读取整个文件,因此ruby必须等到文件结束才能返回文本,这发生在另一端关闭管道时,即当目标程序时已完成执行。您不必一次读取文件整个文件,而是可以逐行读取文件

def process(command)
  IO.popen(command) do |io|
    io.each do |line|
      puts line
    end
  end
end

告诉ruby在找到换行符之前读取文件,然后返回文本......一遍又一遍地获取文件,直到文件结束。

以下是一个完整的例子:

#my_prog.rb

text = ""

1.upto(10) do
  text << "."

  puts text
  STDOUT.flush

  sleep 1
end

...

def process(command)
  IO.popen(command) do |io|
    io.each do |line|
      puts line
    end
  end
end

my_command = 'ruby ./my_prog.rb'
process(my_command)

请注意,除非目标程序刷新输出,否则输出将缓冲,因此在填充缓冲区之前,文本将无法读取(此时缓冲区将自动刷新)或目标程序结束(此时缓冲区也将自动刷新)。您可以只使用程序顶部的行STDOUT.flush(),而不是反复调用STDOUT.sync = true。当sync设置为true时,ruby不会缓冲输出。

答案 1 :(得分:-1)

IO.popen(command){ |f| puts f.lines.to_a }