【问题标题】:Reassigning global $stdout to console - ruby将全局 $stdout 重新分配给控制台 - ruby
【发布时间】:2012-03-04 12:14:41
【问题描述】:

我正在尝试将 $stdout 设置为临时写入文件,然后再返回文件。

test.rb :
   old_stdout = $stdout    
    $stdout.reopen("mytestfile.out",'w+')
       puts "this goes in mytestfile"
    $stdout= old_stdout
puts "this should be on the console"
    $stdout.reopen("mytestfile1.out",'w+')
       puts "this goes in mytestfile1:"
    $stdout = old_stdout
 puts "this should be back on the console"

这是输出。

ruby test.rb => no output on the console
cat mytestfile.out 
  this goes in mytestfile
  this should be on the console
cat  mytestfile1.out
  this goes in mytestfile1:
  this should be back on the console

我不确定为什么 $stdout 没有重置到控制台?

【问题讨论】:

  • 如果您接受其中一个已发布的答案,如果这当然解决了您的问题,我相信有人会很感激!

标签: ruby stdout iostream


【解决方案1】:

这个问题可以通过在更改之前在$stdout上调用dup来解决:

old_stdout = $stdout.dup  
$stdout.reopen("mytestfile.out",'w+')
puts "this goes in mytestfile"
$stdout = old_stdout.dup
puts "this should be on the console"
$stdout.reopen("mytestfile1.out",'w+')
puts "this goes in mytestfile1:"
$stdout = old_stdout
puts "this should be back on the console"

输出:

ruby test.rb
# => this should be on the console
# => this should be back on the console
cat mytestfile.out
# => this goes in mytestfile
cat mytestfile1.out
# => this goes in mytestfile1

以下是我通常将此功能打包成函数的方式:

# Runs a block of code while blocking stdout.
# Note that /dev/null should be changed to NUL on Windows.
def silence_stdout(log = '/dev/null')
  old = $stdout.dup
  $stdout.reopen(File.new(log, 'w'))
  yield
  $stdout = old
end

用法:

silence_stdout 'mytestfile.out' do
  puts "this goes in mytestfile"
end

puts "this should be on the console"

silence_stdout 'mytestfile1.out' do
  puts "this goes in mytestfile1"
end

puts "this should be back on the console"

编辑:正如另一张海报提到的,仅在使用纯 Ruby 代码时才需要使用重新打开。上面的函数既适用于纯 Ruby 代码,也适用于例如写入 STDOUT 的 C 扩展。

【讨论】:

  • 谢谢。这似乎是一个不错的解决方案,但由于某种原因,我在 block_given 上得到了错误?在 !!ruby1.8.7 方法中。接受答案..假设我的代码在某处搞砸了..
  • 我只是在这里钓鱼,但是您是否尝试过将块显式传递给函数?例如。 def silence_stdout(log = '/dev/null', &block)
【解决方案2】:

如果您只是使用 Ruby 代码,则无需使用 reopenputs 和其他 Ruby 方法将使用 $stdout 的当前值,因此您可以重新分配它。

old_stdout = $stdout    
$stdout = File.new("mytestfile.out",'w+')
puts "this goes in mytestfile"
$stdout = old_stdout
puts "this should be on the console"
$stdout = File.new("mytestfile1.out",'w+')
puts "this goes in mytestfile1:"
$stdout = old_stdout
puts "this should be back on the console"

如果您正在执行诸如创建子进程(例如使用fork)之类的操作并且希望子进程的输出到其他地方,或者如果您有一个直接写入标准输出的扩展,则您只需要使用reopen使用 Ruby 的 $stdout 全局。

在您的代码中,当您调用 reopen 时,您正在重定向 both $stdoutold_stdout,因为它们都只是对同一个 IO 对象的引用,这就是为什么您不是当您将old_stdout 分配回stdout 时,不会将输出返回到控制台。

【讨论】:

  • 很好的答案,但您不需要 old_stdout,您可以使用 STDOUT。你也让你的文件保持打开状态(讨厌)。
  • @pguardiario 是的,我只是对问题代码进行了最低限度的更改,以显示他哪里出错了。这当然不是“生产质量”,但希望能更好地理解为什么原始代码不起作用。 (另外,$stdout 可能已经分配给除STDOUT 以外的其他对象,因此可能需要使用old_stdout
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多