Ruby—Open3.popen3/如何打印输出 [英] Ruby—Open3.popen3 / how to print the output
问题描述
我有一个小 ruby 脚本,它以以下方式执行 mysql
导入:mysql -u
,但使用 Open3.popen3
来做到这一点.这就是我到目前为止所拥有的:
I have a little ruby script which does a mysql
import in the way: mysql -u <user> -p<pass> -h <host> <db> < file.sql
, but utilizes Open3.popen3
to do so. That is what I have so far:
mysqlimp = "mysql -u #{mysqllocal['user']} "
mysqlimp << "-h #{mysqllocal['host']} "
mysqlimp << "-p#{mysqllocal['pass']} "
mysqlimp << "#{mysqllocal['db']}"
Open3.popen3(mysqlimp) do |stdin, stdout, stderr, wthr|
stdin.write "DROP DATABASE IF EXISTS #{mysqllocal['db']};\n"
stdin.write "CREATE DATABASE #{mysqllocal['db']};\n"
stdin.write "USE #{mysqllocal['db']};\n"
stdin.write mysqldump #a string containing the database data
stdin.close
stdout.each_line { |line| puts line }
stdout.close
stderr.each_line { |line| puts line }
stderr.close
end
这实际上是在完成工作,但有一件事情让我感到困扰,即我希望看到的输出.
That is actually doing the Job, but there is one thing that bothers me, concerned to the output I would like to see.
如果我将第一行改为:
mysqlimp = "mysql -v -u #{mysqllocal['user']} " #note the -v
然后整个脚本永远挂起.
then the whole script hangs forever.
我猜,发生这种情况是因为读流和写流相互阻塞,而且我还猜想 stdout
需要定期刷新,以便 stdin
会去在被消耗.换句话说,只要 stdout
的缓冲区已满,进程就会等待直到它被刷新,但由于这是在最底部先完成的,所以永远不会发生.
I guess, that happens because the read- and write-stream block each other and I also guess that the stdout
needs to be flushed regularly so that stdin
will go on to be consumed. In other words, as long as the buffer of the stdout
is full, the process will wait until its flushed, but since this is done at the very bottom first, that never happens.
我希望有人可以验证我的理论?我怎么能写出能打印出 stdout
中的所有内容并将所有内容也写入 stdin
的代码?
I hope someone can verify my theory? How could I write code that does prints out everything from the stdout
and writes everything to the stdin
as well?
提前致谢!
推荐答案
- 由于您只写入标准输出,您可以简单地使用
Open3#popen2e
将stdout
和stderr
合并到一个流中. - 要将换行符终止的字符串写入流,您可以像在简单的 hello world 程序中使用
$stdout
一样使用puts
. - 您必须使用
waith_thread.join
或wait_thread.value
等待子进程终止. - 无论如何,如果您想立即查看结果,您必须启动一个单独的线程来从流中读取数据.
- Since you are only writing to stdout, you can simply use
Open3#popen2e
which consolidatesstdout
andstderr
into a single stream. - To write newline terminated strings to a stream, you can use
puts
as you would with$stdout
in a simple hello world program. - You must use
waith_thread.join
orwait_thread.value
to wait until the child process terminates. - In any case, you will have to start a separate thread for reading from the stream, if you want to see the results immediately.
示例:
require 'open3'
cmd = 'sh'
Open3.popen2e(cmd) do |stdin, stdout_stderr, wait_thread|
Thread.new do
stdout_stderr.each {|l| puts l }
end
stdin.puts 'ls'
stdin.close
wait_thread.value
end
您的代码,已修复:
require 'open3'
mysqldump = # ...
mysqlimp = "mysql -u #{mysqllocal['user']} "
mysqlimp << "-h #{mysqllocal['host']} "
mysqlimp << "-p#{mysqllocal['pass']} "
mysqlimp << "#{mysqllocal['db']}"
Open3.popen2e(mysqlimp) do |stdin, stdout_stderr, wait_thread|
Thread.new do
stdout_stderr.each {|l| puts l }
end
stdin.puts "DROP DATABASE IF EXISTS #{mysqllocal['db']};"
stdin.puts "CREATE DATABASE #{mysqllocal['db']};"
stdin.puts "USE #{mysqllocal['db']};"
stdin.close
wait_thread.value
end
这篇关于Ruby—Open3.popen3/如何打印输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!