# Redirecting standard output

**URL:** <https://www.ruby-forum.com/t/redirecting-standard-output/180022>\
**Category:** Ruby\
**Created:** [December 9, 2009, 9:50pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022 "2009-12-09T21:50:36Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 9, 2009, 9:50pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/1 "2009-12-09T21:50:36Z")

</div>

Hi all,

Is there a way to redirect the standard output, so that command like  
puts write to a file instead of the console?

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 10, 2009, 3:48pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/2 "2009-12-10T15:48:44Z")

</div>

Omar C. wrote:

> Hi all,
> 
> Is there a way to redirect the standard output, so that command like  
> puts write to a file instead of the console?

Using this as a way to shamelessly promote my ‘desc\_method’ gem… 🙂

> > $stdout.methods  
> > =\> [:reopen, :print, …]
> 
> > require ‘desc\_method’  
> > =\> true
> 
> > $stdout.desc\_method :reopen  
> > sig: #\<Method: IO#reopen\> arity: -1  
> > appears to be a c method  
> > searching ri for IO#reopen…  
> > -------------------------------------------------------------- IO#reopen  
> > ios.reopen(other\_IO) =\> ios  
> > ios.reopen(path, mode\_str) =\> ios

```
 From Ruby 1.9.1

```

* * *

```
 Reassociates _ios_ with the I/O stream given in _other_IO_ or to a
 new stream opened on _path_. This may dynamically change the actual
 class of this stream.

    f1 = File.new("testfile")
    f2 = File.new("testfile")
    f2.readlines[0] #=> "This is line one\n"
    f2.reopen(f1) #=> #<File:testfile>
    f2.readlines[0] #=> "This is line one\n"

```

(end ri)  
=\> “#\<Method: IO#reopen\>”

> > $stdout.reopen(“abc”, “w”)

Enjoy  
-r

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 2:44am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/3 "2009-12-11T02:44:42Z")

</div>

Thanks, that’s exactly what I was looking for! Nice gem by the way. I  
tried to “gem install” it, but I got a weird error message, don’t  
remember what it was.

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 3:35am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/4 "2009-12-11T03:35:27Z")

</div>

Omar C. wrote:

> Thanks, that’s exactly what I was looking for! Nice gem by the way. I  
> tried to “gem install” it, but I got a weird error message, don’t  
> remember what it was.

No need for a gem.

$stdout = File.new ‘/path/to/file’, ‘w’  
puts ‘foobar’  
$stdout = STDOUT  
puts ‘foobar’

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 8:53am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/5 "2009-12-11T08:53:42Z")

</div>

> Assignment to $stdout is deprecated (at least according to pickaxe),  
> using reopen is the right way to do it:
> 
> $stdout.reopen(File.new("/path/to/file", “w”))

Yup, you can use IO#reopen too. I don’t know about being “deprecated”.

$stdout.reopen will also redirect STDOUT to the location referenced in  
your call to #reopen. How can you redirect $stdout to its original  
location now?

The above solution ensures you can easily switch back.

- Rob

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 8:39am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/6 "2009-12-11T08:39:59Z")

</div>

On 11 déc. 2009, at 03:35, Robert G. wrote:

> $stdout = File.new ‘/path/to/file’, ‘w’  
> puts ‘foobar’  
> $stdout = STDOUT  
> puts ‘foobar’

Assignment to $stdout is deprecated (at least according to pickaxe),  
using reopen is the right way to do it:

$stdout.reopen(File.new("/path/to/file", “w”))

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 9:08am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/7 "2009-12-11T09:08:58Z")

</div>

> Yup, you can use IO#reopen too. I don’t know about being “deprecated”.
> 
> $stdout.reopen will also redirect STDOUT to the location referenced in  
> your call to #reopen. How can you redirect $stdout to its original  
> location now?
> 
> The above solution ensures you can easily switch back.

Answer to my own question:

FOO\_BAR = STDOUT.dup  
$stdout.reopen ‘/foo/bar/baz’, ‘w’  
puts ‘foobar’  
$stdout.reopen FOO\_BAR

This method might be more useful if you want to redirect both $stdout,  
and STDOUT.

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 11:36am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/8 "2009-12-11T11:36:10Z")

</div>

2009/12/11 Robert G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> Omar C. wrote:
> 
> > Thanks, that’s exactly what I was looking for! Nice gem by the way. I  
> > tried to “gem install” it, but I got a weird error message, don’t  
> > remember what it was.
> 
> No need for a gem.

The gem was not needed for the redirection functionality but for  
getting at information about the method.

> $stdout = File.new ‘/path/to/file’, ‘w’  
> puts ‘foobar’  
> $stdout = STDOUT  
> puts ‘foobar’

This does only work for redirections of output for the particular  
process. It will fail in these cases

- sub processes started
- all entities which remembered $stdout instance (e.g. a logger)

Your last solution is better (although you do not necessarily need a  
constant for that). Btw, apparently you don’t even need the mode -  
that is inherited from the original. So you can do:

$ ruby19 -e ‘$stderr.reopen(“log”); $stderr.puts(“foo”)’ ; cat log  
foo  
$ ruby19 -e ‘$stdin.reopen(“log”); p gets’  
“foo\n”  
$

Cheers

robert

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 4:35pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/9 "2009-12-11T16:35:14Z")

</div>

2009/12/11 Robert G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> > This does only work for redirections of output for the particular  
> > $ cat foobar.txt  
> > Hello  
> > =\> 4301
> 
> Am I misunderstanding you?

I probably wasn’t specific enough: sub processes which use exec to  
overlay the image will not inherit redirection if you simply assign to  
$stdout:

16:24:59 ~$ ruby19 -e ‘$stdout = File.open(“log”,“w”); puts 123;  
system(“date”)’  
Fri Dec 11 16:25:05 WEST 2009  
16:25:05 ~$ cat -n log  
1 123  
16:25:08 ~$ ruby19 -e ‘$stdout.reopen(“log”); puts 456; system(“date”)’  
16:25:14 ~$ cat -n log  
1 456  
2 Fri Dec 11 16:25:13 WEST 2009  
16:25:15 ~$

> persist.  
> And exactly that is a problem: redirection does not take place for  
> whoever owns foo =\> it failed.

Cheers

robert

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 2:49pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/10 "2009-12-11T14:49:12Z")

</div>

> The gem was not needed for the redirection functionality but for  
> getting at information about the method.  
> Yup, I completely missed that! I was tired, and misread the thread  
> completely.

> > $stdout = File.new ‘/path/to/file’, ‘w’  
> > puts ‘foobar’  
> > $stdout = STDOUT  
> > puts ‘foobar’
> 
> This does only work for redirections of output for the particular  
> process. It will fail in these cases
> 
> - sub processes started

Hmm really? I thought a fork() would copy the memory from the parent  
process into the subprocess.  
Example:

$stdout = File.open ‘foobar.txt’, ‘w’; fork { $stdout.puts ‘Hello’ }

$ cat foobar.txt  
Hello  
=\> 4301

Am I misunderstanding you?

> - all entities which remembered $stdout instance (e.g. a logger)

I’m not sure I follow you here either.  
A reference to $stdout would persist.

foo = $stdout  
$stdout = File.new ‘foobar.txt’, ‘w’

# foo still references $stdout

Unless they use #dup, I don’t see how the reference to $stdout wouldn’t  
persist.

> Your last solution is better (although you do not necessarily need a  
> constant for that).

Yup. I just choose a constant to illustrate an example - if $stdout was  
changing often, I’d use something more appropriate.

> Btw, apparently you don’t even need the mode -  
> that is inherited from the original. So you can do:
> 
> $ ruby19 -e ‘$stderr.reopen(“log”); $stderr.puts(“foo”)’ ; cat log  
> foo  
> $ ruby19 -e ‘$stdin.reopen(“log”); p gets’  
> “foo\n”  
> $

Cool, good to know

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 5:08pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/11 "2009-12-11T17:08:15Z")

</div>

> I probably wasn’t specific enough: sub processes which use exec to  
> overlay the image will not inherit redirection if you simply assign to  
> $stdout:
> 
> 16:24:59 ~$ ruby19 -e ‘$stdout = File.open(“log”,“w”); puts 123;  
> system(“date”)’  
> Fri Dec 11 16:25:05 WEST 2009  
> 16:25:05 ~$ cat -n log  
> 1 123  
> 16:25:08 ~$ ruby19 -e ‘$stdout.reopen(“log”); puts 456; system(“date”)’  
> 16:25:14 ~$ cat -n log  
> 1 456  
> 2 Fri Dec 11 16:25:13 WEST 2009  
> 16:25:15 ~$

Ah! Okay. It makes sense now 🙂 Cool, I didn’t know that.

> > persist.  
> > And exactly that is a problem: redirection does not take place for  
> > whoever owns foo =\> it failed.

“whoever owns foo =\> it failed?” …? I don’t see any difference between  
assigning $stdout and using $stdout.reopen in this case.

foo = $stdout = File.open ‘foo’, ‘w’  
foo = $stdout.reopen ‘foo’, ‘w’

They’re both references to the same object. Can you elaborate or provide  
an example? Thanks.

- Rob

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 5:22pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/12 "2009-12-11T17:22:04Z")

</div>

2009/12/11 Robert G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> > > persist.  
> > > And exactly that is a problem: redirection does not take place for  
> > > whoever owns foo =\> it failed.
> 
> “whoever owns foo =\> it failed?” …? I don’t see any difference between  
> assigning $stdout and using $stdout.reopen in this case.
> 
> foo = $stdout = File.open ‘foo’, ‘w’  
> foo = $stdout.reopen ‘foo’, ‘w’

That is not a proper model of the situation.

> They’re both references to the same object. Can you elaborate or provide  
> an example? Thanks.

Now I’m tired and leave that as exercise for the reader.

Cheers

robert

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 5:30pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/13 "2009-12-11T17:30:43Z")

</div>

Can anyone else provide an example?

> This does only work for redirections of output for the particular  
> process. It will fail in these cases
> 
> - sub processes started # thats cleared up.
> - all entities which remembered $stdout instance (e.g. a logger) # huh?

I don’t see how reassignment or #reopen would make a difference. They  
reference the same object after all - for this particular case, their  
behavior is the same.

So what gives?

- Rob

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 11, 2009, 8:45pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/14 "2009-12-11T20:45:10Z")

</div>

On 12/11/2009 05:30 PM, Robert G. wrote:

> So what gives?

I suggest you look again at my earlier posting (the one with the “date”  
example) and / or look at the documentation. There _is_ a difference  
between reassigning and using #reopen - and it is significant.

Cheers

robert

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 14, 2009, 4:12am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/15 "2009-12-14T04:12:48Z")

</div>

I don’t know many of the technical aspects like subprocesses, but what I  
did was this:

At the beginning of my program:  
$stderr2 = $stderr.clone  
$stderr.reopen(‘tmp2.dat’)

At the end:  
$stderr.reopen($stderr2)  
exit

Worked like a charm!

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 12, 2009, 5:29am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/16 "2009-12-12T05:29:55Z")

</div>

Robert K. wrote:

> On 12/11/2009 05:30 PM, Robert G. wrote:
> 
> > So what gives?
> 
> I suggest you look again at my earlier posting (the one with the “date”  
> example) and / or look at the documentation. There _is_ a difference  
> between reassigning and using #reopen - and it is significant.
> 
> Cheers
> 
> robert

Yup, I’ve acknowledged the difference myself in all my previous posts.  
I just couldn’t understand your second argument, but I think I know what  
you mean from playing around in IRB.

Reassignment will create a new object… so

# $stdout references a new object - foo references old.

foo = $stdout  
$stdout = File.open ‘foo’, ‘w’

# $stdout.reopen will keep the same object identity…

# So all previous references will persist.

foo = $stdout  
$stdout.reopen ‘foo’, ‘w’

Understood now. I can sleep.

- Rob

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 14, 2009, 10:57am UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/17 "2009-12-14T10:57:59Z")

</div>

Robert G. wrote:

> I don’t see how reassignment or #reopen would make a difference. They  
> reference the same object after all - for this particular case, their  
> behavior is the same.
> 
> So what gives?

When you assign to $stdout, you are only changing the Ruby global  
variable called ‘$stdout’

As it happens, Kernel#puts is just a shorthand for $stdout.puts, so it  
will do what you expect. But the _real_ stdout of the process (that is,  
file descriptor 1 in the process’ FD table) is untouched. You can still  
get at it using the STDOUT constant, or IO.new(1).

When you do $stdout.reopen(f), you are actually re-opening FD 1 with a  
different file - underneath, ruby is doing a dup2() call to copy  
f.fileno to FD 1. This means that the process’ actual stdout has  
changed. This is what gets inherited by children you fork off.

So:

$ ruby -e ‘$stdout = File.open("/dev/null",“w”); system(“echo hello”)’  
hello  
$ ruby -e ‘$stdout.reopen(File.open("/dev/null",“w”)); system(“echo  
hello”)’  
$

As for deprecation: I have a suspicion it’s $defout not $stdout which is  
deprecated.

---

<div class="post-metadata">

**Author:** ![tutiplain](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/77aa72/32.png) [@tutiplain](https://www.ruby-forum.com/u/tutiplain)\
**Post date:** [December 14, 2009, 3:55pm UTC](https://www.ruby-forum.com/t/redirecting-standard-output/180022/18 "2009-12-14T15:55:25Z")

</div>

Howdy,

Thanks for clarification. If you read the entire thread, you’d see:

> > I don’t see how reassignment or #reopen would make a difference. They  
> > reference the same object after all - for this particular case, their  
> > behavior is the same.
> > 
> > So what gives?

Refers to wondering how reassignment of $stdout & #reopen would make any  
difference to previous references to $stdout. It’s cleared up now, as I  
understand #reopen won’t change object identity but reassignment  
obviously will.

Thanks for the rest of your post.

- Rob
