简体   繁体   English

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

[英]How do I display the popen output as it happens through a get request?

I have some Ruby scripts that I use to automate some rsync tasks that can take a very long time to finish. 我有一些Ruby脚本可用来自动执行一些rsync任务,这些任务可能需要很长时间才能完成。 I'm using popen to run a command: 我正在使用popen运行命令:

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

The command is executed by a get request in a Sinatra app: 该命令由Sinatra应用程序中的get请求执行:

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

Then I am accessing the output with an Ajax request on the front end: 然后,我在前端使用Ajax请求访问输出:

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

Is it possible to display the shell output as it happens rather than only having it return at the end of the process? 是否可以在发生过程中显示shell输出,而不是仅在过程结束时返回它?

IO::popen: IO :: popen:

Runs the specified command as a subprocess; 将指定的命令作为子进程运行; the subprocess's standard input and output will be connected to the returned IO object. 子进程的标准输入和输出将连接到返回的IO对象。

stdout is a file. stdout是一个文件。 You are telling ruby to read the whole file with the line io.read , therefore ruby has to wait until the end of file is reached to return the text, which happens when the other end closes the pipe, ie when the target program has finished executing. 您要告诉ruby使用io.read行读取整个文件,因此ruby必须等到到达文件末尾才能返回文本,这发生在另一端关闭管道时,即目标程序完成时执行。 You don't have to read a file a whole file at a time , instead you can read a file line by line : 您不必一次读取整个文件 ,而可以逐行读取文件:

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

That tells ruby to read the file until it finds a newline, then return the text...over and over gain until the end of file is reached. 这告诉ruby读取文件,直到找到换行符,然后返回文本……反复获取直到到达文件末尾。

Here's a full example: 这是一个完整的示例:

#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)

Note that unless the target program flushes the output, the output will be buffered , and therefore the text won't be available to be read until the buffer is filled (at which point the buffer will be flushed automatically) or the target program ends(at which point the buffer also will be flushed automatically). 请注意,除非目标程序刷新了输出,否则输出将被缓冲 ,因此在缓冲区被填满(此时将自动刷新缓冲区)或目标程序结束之前,将无法读取文本。这时缓冲区也将自动刷新)。 Instead of calling STDOUT.flush() repeatedly, you can just use the line STDOUT.sync = true at the top of your program. 不必重复调用STDOUT.flush() ,而只需在程序顶部使用STDOUT.sync = true行。 When sync is set to true, ruby won't buffer the output. 当sync设置为true时,ruby不会缓冲输出。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM