From: Joel VanderWerf Date: 2005-02-25T08:22:54+09:00 Subject: Re: How to extend $stdout#write for system calls? Jim Freeze wrote: > * Joel VanderWerf [2005-02-25 07:19:12 +0900]: > > >>How could this work if echo is not even a ruby program? Maybe if you run >>echo with popen, and print the output of that... But if you want it to >>work with arb. ruby code, this won't help. > > > It may not be possible. My knowledge of $stdout doesn't run too deep. > So far, I have wrapped the write call, so puts is captured and I > have reopened stdout to write to a file. So, I figured there should > be a way to capture a system call (since it inherits $stdout from the > current process). A child process inherits the file handle that $stdout refers to, but not the ruby object itself, even if the child process is ruby. > The idea is to do the following: > > IO::Tee(file) { > # all output is to go to file and screen > puts "from ruby puts" > system("echo", "from system") > exec("echo", "from system") > } > > and have the contents of file and the screen be identical. You'll be disappointed by the following if you are using windows, but what else is new. ------ class IO def tee IO.popen("-") do |pipe| # Won't work on mswin. if pipe # parent while (str = pipe.gets) puts str $stdout.puts str end else # child yield end end end end f=File.open("/tmp/tee-example-output", "w+") f.tee do puts "something" puts "something else" end f.rewind puts "The contents of file is:\n#{f.read.inspect}" ------- output: something something else The contents of file is: "something\nsomething else\n" Note that the "tee" block is executed in a child process, so state (e.g. local vars) will not be changed when you get back to the main process.