Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redirect stdout/stderr to file under unix c++ - again

What I want to do

redirect stdout and stderr to one or more files from inside c++

Why I need it

I am using an external, precompiled third-party library that produces a ridiculous amount of output, which I would like to redirect to a log file to keep the console clean.

Conditions

Compatibility is not a problem, the code will only run on Unix systems. The redirection should not only affect c++-style printing (std::cout << "hello world" << std::endl), but also c-style printing (printf("hello world\n")).

What I have tried so far

I have been browsing on stackoverflow for half a day, reading multiple answers to people having similar problems. With the help of these answers, I have been able to put together the following piece of code:


#include <stdio.h>
#include <iostream>
#include <fcntl.h>
#include "unistd.h"

const int stdoutfd(dup(fileno(stdout)));

int redirect_stdout(const char* fname){
  fflush(stdout);
  int newstdout = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |     S_IROTH);
  dup2(newstdout, fileno(stdout));
  close(newstdout);
}

int restore_stdout(){
  fflush(stdout);
  dup2(stdoutfd, fileno(stdout));
  close(stdoutfd);
  return stdoutfd;
}

int main(){
  redirect_stdout("/dev/null");
  std::cout << "invisible 1" << std::endl;
  restore_stdout();
  std::cout << "visible 1" << std::endl;
  redirect_stdout("/dev/null");
  std::cout << "invisible 2" << std::endl;
  restore_stdout();
  std::cout << "visible 2" << std::endl;
  return 0;
}

What I would expect to see:

visible 1
visible 2

What I actually see

visible 1

That is, when using this mechanism for the first time, it works - but if used again, restoring the output will not work. Can somebody point out to me what I need to change in order to have the mechanism work infinitely often?

like image 213
carsten Avatar asked Aug 06 '13 17:08

carsten


People also ask

How do I redirect stdout and stderr to the same file?

Redirecting stdout and stderr to a file: The I/O streams can be redirected by putting the n> operator in use, where n is the file descriptor number. For redirecting stdout, we use “1>” and for stderr, “2>” is added as an operator.

How do you redirect stderr to stdout?

Understanding the concept of redirections and file descriptors is very important when working on the command line. To redirect stderr and stdout , use the 2>&1 or &> constructs.

Can stderr be redirected?

The regular output is sent to Standard Out (STDOUT) and the error messages are sent to Standard Error (STDERR). When you redirect console output using the > symbol, you are only redirecting STDOUT. In order to redirect STDERR, you have to specify 2> for the redirection symbol.


2 Answers

In addition to afr0ck answer of freopen() I want to say that while using freopen() we should be careful. Once a stream like stdout or stdin is reopened with assigning the new destination(here the 'output.txt' file) always it remains for a program unless it has been explicitly change.

freopen("output.txt", "a", stdout);

Here the standard output stream stdout is reopened and assigned with the 'output.txt' file. After that whenever we use printf() or any other stdout stream like - putchar() then every output will goes to the 'output.txt'. To get back the default behavior (that is printing the output in console/terminal) of printf() or putchar() we can use the following line of code -

  • for gcc, linux distribution like ubuntu - freopen("/dev/tty", "w", stdout);
  • for Mingw C/C++, windows - freopen("CON", "w", stdout);

See the code example below -

#include <stdio.h>

int main() {
    
    printf("No#1. This line goes to terminal/console\n");

    freopen("output.txt", "a", stdout);
    printf("No#2. This line goes to the \"output.txt\" file\n");
    printf("No#3. This line aslo goes to the \"output.txt\" file\n");

    freopen("/dev/tty", "w", stdout); /*for gcc, diffrent linux distro eg. - ubuntu*/
    //freopen("CON", "w", stdout); /*Mingw C++; Windows*/
    printf("No#4. This line again goes to terminal/console\n");        

}

This code generate a 'output.txt' file in your current directory and the No#2 and No#3 will be printed in the 'output.txt' file.

Thanks

like image 159
Razib Avatar answered Nov 15 '22 16:11

Razib


If you want to be able to reuse it, don't close stdoutfd in restore_stdout.

like image 43
Casey Avatar answered Nov 15 '22 16:11

Casey