29

I am working with a multi-thread program.

First I redirect my stdout to a certain file. No problem there (I used dup2(fd, 1) where fd is the file descriptor for the file).

Afterwards, I need to redirect my stdout to the terminal again.

My first approach:

      /*Declaration*/
      fpost_t  stream_sdout;
      /*code*/
      if ( fgetpos( stdout, &stream_sdout) == -1 )
          perror(Error:);

It says illegal seek.
No idea why this is happening.
But if I get this to work, then I only need to use fsetpos(stdout, &stream_stdout) and it should work.

My second idea, was to to copy the stdout using dup2(stdout, 4) to the file descriptor table, at position 4. But that ain't working either.

How can I switch the standard output back to its original destination (terminal, pipe, file, whatever)?

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Alessandroempire
  • 1,640
  • 4
  • 31
  • 54
  • I have a feeling that trying to move `stdout` around like this is probably a bad idea -- what position exactly should the _terminal_ report in `fgetpos()`? Why not simply open a file and output to it using `fwrite()` or `fprintf()` or `write()` and output to the terminal via `/dev/tty` when you need it? – sarnold Jun 14 '12 at 22:30
  • 1
    @sarnold: probably because the program has libraries or other unalterable code which are hardwired to `stdout`. – wallyk Jun 14 '12 at 22:31
  • @sarnold i actually didnt give it thought to that posibility. Let me check quickly. – Alessandroempire Jun 14 '12 at 22:37
  • I don't have enough information to post a good answer, so I'm commenting instead. In Windows, you can re-attach the console. I'd look at any Win32 SDK documentation. It's not hard; I just can't remember how to do it. – octopusgrabbus Jun 14 '12 at 22:49
  • @sarnold thanks for the advice! That was much easier. I was able to make it work to perfection. I still have the doubt if restoring the std is possible, but your solution got me out of a tight spot. Thanks! – Alessandroempire Jun 14 '12 at 22:54
  • @Alessandroempire: [wallyk's answer covers _restoring the stdout_](http://stackoverflow.com/a/11042281/377270) very nicely. :) – sarnold Jun 14 '12 at 23:05
  • Before tweaking it you could first save the original stdout fd by a dup2() (use fileno) and save the dupped fd for later. Dont forget to flush. – wildplasser Jun 14 '12 at 23:13
  • You can't seek on a terminal (or on a pipe). – Jonathan Leffler Jun 14 '12 at 23:17

3 Answers3

53
#include <unistd.h>

...

int saved_stdout;

...

/* Save current stdout for use later */
saved_stdout = dup(1);
dup2(my_temporary_stdout_fd, 1);

... do some work on your new stdout ...

/* Restore stdout */
dup2(saved_stdout, 1);
close(saved_stdout);
pilcrow
  • 56,591
  • 13
  • 94
  • 135
  • This really helped me out a lot. I was wondering though what is the function of close(saved_stdout)? I've used close for closing files but I am not yet familiar with how the whole dup function process works. – ThinkBonobo Apr 13 '14 at 19:22
  • 4
    @ThinkBonobo, `saved_stdout` is a duplicate (hence, *dup()*) of the original file descriptor for the original file underlying the program's stdout. When is it again duplicated back to (*dup2()*) stdout (file descriptor no. 1), the program has two copies/handles/descriptors for the same underlying file. There's no need for this once the output redirection is finished (and it might confound resource limits or assumptions about file locks, etc.), so good practice is to dismiss the resource when no longer needed. – pilcrow Apr 15 '14 at 15:44
13

Before you do the dup2(fd, STDOUT_FILENO), you should save the current open file descriptor for standard output by doing int saved_stdout = dup(STDOUT_FILENO); (letting dup() choose an available file descriptor number for you). Then, after you've finished with the output redirected to a file, you can do dup2(saved_stdout, STDOUT_FILENO) to restore standard output to where it was before you started all this (and you should close saved_stdout too).

You do need to worry about flushing standard I/O streams (fflush(stdout)) at appropriate times as you mess around with this. That means 'before you switch stdout over'.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

If the program runs on a Linux environment, you can freopen ("/dev/stdout", "a", stdout).

But if you know that stdout was the terminal, freopen ("/dev/tty", "a", stdout) or the equivalent for other OSs—even Windows.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • 1
    When the `dup2()` works, `/dev/stdout` should refer to the file. So you've switched the output from the file to the file, I believe. – Jonathan Leffler Jun 14 '12 at 23:02
  • @JonathanLeffler: If he is changing the `fd`s around, that would be true. It is far from apparent from his description that is what is happening. It seems he might be changing around the FILE connections instead. – wallyk Jun 14 '12 at 23:11
  • Since he mentions using `dup2()` to switch the standard output, it seems to me he is messing with file descriptors to start with. The code to reset things in the question is weird beyond rescue; a rewrite is in order. But that's what the answers are supposed to be about, of course. – Jonathan Leffler Jun 14 '12 at 23:15