0

Is it possible to create (from the shell/Bash or within a C++ program) an additional file descriptor like STDOUT/STDERR? I.e. by default it should write all output to the terminal and mix both outputs, but if I wanted to I could redirect them selectively?

My use case is a MPI-parallel C++ program running in multiple-program-multiple-data (MPMD) mode, i.e. several unrelated functional entities are running simultaneously using different data sets. What I would like to achieve is that by default, all output gets send to the terminal, but that I would be able to redirect one or more of the output streams to e.g. a file.

  • 1
    You can always have your program take a filename as an optional argument for its output… lots of programs are designed this way. – gniourf_gniourf Sep 21 '15 at 11:34
  • Indeed, this is one (of several) alternative ways to achieve a similar effect. What that would it take to make my approach work (if nothing else, just for the sake of it)? – Michael Schlottke-Lakemper Sep 21 '15 at 11:44

2 Answers2

1

Standard output and standard error have the file descriptors of 1 and 2, respectively. When you start a program, file descriptors are by default inherited by the child process. Thus, if you open a file descriptor (e.g. 3) before starting a program, it will be able to use it just as if it were another special FD like stdout or stderr. You can open an FD for writing like this in bash:

exec 3>/some/file

Note, however, that while shells usually propagate open file descriptors to their children, some programs that spawn other programs may have another policies. For example, nohup redirects the standard FDs but does not touch any others. Other programs, while unlikely, may close all FDs above 2.

petersohn
  • 11,292
  • 13
  • 61
  • 98
  • How would I access this new file descriptor `3` from C++ then? – Michael Schlottke-Lakemper Sep 22 '15 at 14:18
  • There is no platform independent way of doing it. You can use the native API of your platform, or try some tricks to access native FDs with the standard iostream library: http://stackoverflow.com/questions/2746168/how-to-construct-a-c-fstream-from-a-posix-file-descriptor – petersohn Sep 22 '15 at 14:24
  • Maybe the Boost Iostreams library also has something that you want: http://www.boost.org/doc/libs/1_59_0/libs/iostreams/doc/index.html – petersohn Sep 22 '15 at 14:27
0

You can also duplicate a file descriptor from within your programm, though be aware that this won't play nice with C++ streams.

To duplicate some open file descriptor, you call dup(fd) and get back the next free file descriptor, opened to the same file as the fd descriptor.

For redirection, you can use dup2(old, new), which is the same as closing new and then opening it to the same file as old.

What's important is that when using above functions to duplicate or redirect IO, the respective file descriptors will be pointing to the same file description, which means they share file position and some other information.

I made a small demonstrative example, though I had a hard time getting it to work under the restrictions of ideone:

#include <unistd.h>
int main(void) {
  // duplicate stdout
  int duplicate = dup(1);
  unsigned counter = 0;
  for (; counter < 10; ++counter) {
    if (counter % 2 == 0) {
      // redirect IO on FD duplicate to stderr
      dup2(2, duplicate);
    } else {
      // redirect it back to stdout
      dup2(1, duplicate);
    }
    write (duplicate, "A ", 2);
    write (1, "B\n", 2);
  }
  close (duplicate);
  return 0;
}

You can find further information about that here.

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63