Outputting Stdout to a File and Back Again

Outputting STDOUT To A File And Back Again

UPDATED

orig_std_out = STDOUT.clone
STDOUT.reopen(File.open('OUTPUT', 'w+'))
puts "test to file"
STDOUT.reopen(orig_std_out)
puts "test to screen"

C restore stdout to terminal

#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);

Redirect stdout to a file

What your code essentially does is that you open a pipe, then fork the process and in the child process (in commented code) close stdout, duplicate the pipe to stdout and execute and ls command, and then (in non-commented code) write 4 bytes to the pipe. In the parent process, you read data from the pipe and wait for the completion of the child process.

Now you want to redirect stdout to a file. You can do that by opening a file using the open() system call and then duplicating that file descriptor to stdout. Something like (I haven't tested this so beware of bugs in the code):

int filefd = open("foo.txt", O_WRONLY|O_CREAT, 0666);
if (!fork()) {
close(1);//Close stdout
dup(filefd);
execlp("ls", "ls", NULL);
} else {
close(filefd);
wait(NULL);
}
return 0;

However, you can also use the freopen as suggested by the other answer.

However, I have several concerns of your code and of my modified code:

  • The pipe() and open() system calls can fail. You should always check for system call failure.

  • The fork() system call can fail. Ditto.

  • dup2() can be used instead of dup(); otherwise the code will fail if stdin is not open as it duplicates to the first available file descriptor.

  • The execlp() system call can fail. Ditto.

  • I think wait() can be interrupted by a signal (EINTR). It's recommended to wrap it around a wrapper that retries the system call if it's aborted by a signal (errno == EINTR).

Redirecting output to file then back to console in C++

Probably what you are looking for is rdbuf() as mentioned by doomista in the comments.

Here is a way to redirect Output.

#include <iostream>
#include <fstream>

int main()
{
/** backup cout buffer and redirect to out.txt **/
std::ofstream out("out.txt");

auto *coutbuf = std::cout.rdbuf();
std::cout.rdbuf(out.rdbuf());

std::cout << "This will be redirected to file out.txt" << std::endl;

/** reset cout buffer **/
std::cout.rdbuf(coutbuf);

std::cout << "This will be printed on console" << std::endl;

return 0;
}

Redirect stdout back to console

With thanks to the articles in the comments above I found the information I needed. The dup and dup2 functions were what I needed. Note that based on info here dup and dup2 are deprecated in favour or _dup and _dup2. A working example can be found on MSDN here, but is duplicated below in case the link breaks in the future.

// crt_dup.c
// This program uses the variable old to save
// the original stdout. It then opens a new file named
// DataFile and forces stdout to refer to it. Finally, it
// restores stdout to its original state.

#include <io.h>
#include <stdlib.h>
#include <stdio.h>

int main( void )
{
int old;
FILE *DataFile;

old = _dup( 1 ); // "old" now refers to "stdout"
// Note: file descriptor 1 == "stdout"
if( old == -1 )
{
perror( "_dup( 1 ) failure" );
exit( 1 );
}
_write( old, "This goes to stdout first\n", 26 );
if( fopen_s( &DataFile, "data", "w" ) != 0 )
{
puts( "Can't open file 'data'\n" );
exit( 1 );
}

// stdout now refers to file "data"
if( -1 == _dup2( _fileno( DataFile ), 1 ) )
{
perror( "Can't _dup2 stdout" );
exit( 1 );
}
puts( "This goes to file 'data'\n" );

// Flush stdout stream buffer so it goes to correct file
fflush( stdout );
fclose( DataFile );

// Restore original stdout
_dup2( old, 1 );
puts( "This goes to stdout\n" );
puts( "The file 'data' contains:" );
_flushall();
system( "type data" );
}

How do I get both STDOUT and STDERR to go to the terminal and a log file?

Use "tee" to redirect to a file and the screen. Depending on the shell you use, you first have to redirect stderr to stdout using

./a.out 2>&1 | tee output

or

./a.out |& tee output

In csh, there is a built-in command called "script" that will capture everything that goes to the screen to a file. You start it by typing "script", then doing whatever it is you want to capture, then hit control-D to close the script file. I don't know of an equivalent for sh/bash/ksh.

Also, since you have indicated that these are your own sh scripts that you can modify, you can do the redirection internally by surrounding the whole script with braces or brackets, like

#!/bin/sh
{
... whatever you had in your script before
} 2>&1 | tee output.file


Related Topics



Leave a reply



Submit