如何使用 Ruby 和 IO.popen 写入和读取进程?

发布于 2024-09-18 02:02:33 字数 393 浏览 6 评论 0原文

我写了这个,但它不起作用......

output = IO.popen("irb", "r+") do |pipe|
  pipe.gets
  pipe.puts "10**6"
  pipe.gets
  pipe.puts "quit"
end

我重写了

IO.popen("irb", "w+") do |pipe|
  3.times {puts pipe.gets} # startup noise
  pipe.puts "10**6\n"
  puts pipe.gets # I expect " => 1000000"
  pipe.puts "quit" # I expect exit from irb
end 
but It didn`t work too

I wrote this, but it didn`t work...

output = IO.popen("irb", "r+") do |pipe|
  pipe.gets
  pipe.puts "10**6"
  pipe.gets
  pipe.puts "quit"
end

I rewrite so

IO.popen("irb", "w+") do |pipe|
  3.times {puts pipe.gets} # startup noise
  pipe.puts "10**6\n"
  puts pipe.gets # I expect " => 1000000"
  pipe.puts "quit" # I expect exit from irb
end 

but It didn`t work too

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦中楼上月下 2024-09-25 02:02:33

一般来说,上面的示例将挂起,因为管道仍然打开用于写入,并且您调用的命令(Ruby 解释器)需要更多命令/数据。

另一个答案将 __END__ 发送到 ruby​​ - 这在这里有效,但这个技巧当然不适用于您可能通过 popen 调用的任何其他程序。

当您使用popen时,您需要使用IO#close_write关闭管道。

 IO.popen("ruby", "r+") do |pipe|
   pipe.puts "puts 10**6"

   pipe.close_write    # make sure to close stdin for the program you call

   pipe.gets
 end

请参阅:Ruby 3.1 popen*


更多详细信息:

在 Ruby 中,IO.popenIO.popen2IO.popen2eIO.popen3 是用于处理子进程的方法,它们的不同之处在于处理输入、输出和错误流的方式。以下是对差异以及何时使用每个差异的解释:

  1. IO.popen

    • IO.popen 是一种多功能方法,允许您创建子进程并与其标准输入和输出交互。
    • 它返回一个数组,其中包含子进程的标准输入、标准输出和代表子进程的线程。
    • 当您需要向流程发送数据并捕获其输出时,它适合基本的子流程交互。
    • 示例:
      stdin, stdout, thr = IO.popen('some_command')
      
  2. IO.popen2

    • IO.popen2 创建一个带有单独管道的子进程,用于标准输入和输出。
    • 它返回一个包含子进程的标准输入和输出流的数组。
    • 当您想要向进程发送数据并单独捕获其输出时,它非常有用。
    • 示例:
      stdin, stdout = IO.popen2('some_command')
      
  3. IO.popen2e

    • IO.popen2eIO.popen2 类似,但它将标准输出和标准错误流合并到单个流中。
    • 它返回一个数组,其中包含子进程的标准输入和组合的标准输出/错误流。
    • 当您想要同时捕获输出和错误消息时,这非常有用。
    • 示例:
      stdin, stdout_err = IO.popen2e('some_command')
      
  4. IO.popen3

    • IO.popen3 创建一个子进程,其中包含用于标准输入、标准输出和标准错误的单独管道。
    • 它返回一个数组,其中包含子进程的标准输入、标准输出、标准错误以及代表子进程的线程。
    • 它适用于需要与流程交互、捕获其输出并单独处理潜在错误消息的场景。
    • 示例:
      stdin、stdout、stderr、thr = IO.popen3('some_command')
      

何时使用每个版本取决于您的具体要求:

  • 当您需要与子进程的输入和输出交互并且不需要单独处理错误消息时,请使用 IO.popen

  • 当您想要与标准输入分开捕获标准输出并需要向进程发送数据时,请使用IO.popen2

  • 当您想要在单个流中同时捕获标准输出和标准错误时,请使用 IO.popen2e。

  • 当您需要单独的管道用于标准输入、标准输出和标准错误,并且希望与子进程交互并分别捕获输出和错误消息时,请使用 IO.popen3。

In general the above example will hang because the pipe is still open for writing, and the command you called (the ruby interpreter) expects further commands / data.

The other answer sends __END__ to ruby -- this works here, but this trick will of course not work with any other programs you might call via popen.

When you use popen you need to close the pipe with IO#close_write.

 IO.popen("ruby", "r+") do |pipe|
   pipe.puts "puts 10**6"

   pipe.close_write    # make sure to close stdin for the program you call

   pipe.gets
 end

See: Ruby 3.1 popen*


In more Detail:

In Ruby, IO.popen, IO.popen2, IO.popen2e, and IO.popen3 are methods used for working with subprocesses, and they differ in how they handle input, output, and error streams. Here's an explanation of the differences and when to use each:

  1. IO.popen:

    • IO.popen is a versatile method that allows you to create a subprocess and interact with its standard input and output.
    • It returns an array containing the subprocess's standard input, standard output, and a thread representing the subprocess.
    • It's suitable for basic subprocess interaction when you need to send data to the process and capture its output.
    • Example:
      stdin, stdout, thr = IO.popen('some_command')
      
  2. IO.popen2:

    • IO.popen2 creates a subprocess with separate pipes for standard input and output.
    • It returns an array containing the subprocess's standard input and output streams.
    • It's useful when you want to send data to the process and capture its output separately.
    • Example:
      stdin, stdout = IO.popen2('some_command')
      
  3. IO.popen2e:

    • IO.popen2e is similar to IO.popen2, but it combines the standard output and standard error streams into a single stream.
    • It returns an array containing the subprocess's standard input and combined standard output/error streams.
    • This is useful when you want to capture both output and error messages together.
    • Example:
      stdin, stdout_err = IO.popen2e('some_command')
      
  4. IO.popen3:

    • IO.popen3 creates a subprocess with separate pipes for standard input, standard output, and standard error.
    • It returns an array containing the subprocess's standard input, standard output, standard error, and a thread representing the subprocess.
    • It's suitable for scenarios where you need to interact with the process, capture its output, and handle potential error messages separately.
    • Example:
      stdin, stdout, stderr, thr = IO.popen3('some_command')
      

When to use each version depends on your specific requirements:

  • Use IO.popen when you need to interact with a subprocess's input and output and don't require separate handling of error messages.

  • Use IO.popen2 when you want to capture the standard output separately from the standard input and need to send data to the process.

  • Use IO.popen2e when you want to capture both standard output and standard error together in a single stream.

  • Use IO.popen3 when you need separate pipes for standard input, standard output, and standard error, and you want to interact with the subprocess and capture both output and error messages separately.

为人所爱 2024-09-25 02:02:33

要么做

IO.popen("ruby", "r+") do |pipe|
  pipe.puts "puts 10**6"
  pipe.puts "__END__"
  pipe.gets
end

,要么做

IO.popen("irb", "r+") do |pipe|
  pipe.puts "\n"
  3.times {pipe.gets} # startup noise
  pipe.puts "puts 10**6\n"
  pipe.gets # prompt
  pipe.gets
end

Either do

IO.popen("ruby", "r+") do |pipe|
  pipe.puts "puts 10**6"
  pipe.puts "__END__"
  pipe.gets
end

or do

IO.popen("irb", "r+") do |pipe|
  pipe.puts "\n"
  3.times {pipe.gets} # startup noise
  pipe.puts "puts 10**6\n"
  pipe.gets # prompt
  pipe.gets
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文