Restoring Stdout and Stderr to Default Value

Restoring stdout and stderr to default value

This example

Example 20-2. Redirecting stdout using exec

#!/bin/bash
# reassign-stdout.sh

LOGFILE=logfile.txt

exec 6>&1 # Link file descriptor #6 with stdout.
# Saves stdout.

exec > $LOGFILE # stdout replaced with file "logfile.txt".

# ----------------------------------------------------------- #
# All output from commands in this block sent to file $LOGFILE.

echo -n "Logfile: "
date
echo "-------------------------------------"
echo

echo "Output of \"ls -al\" command"
echo
ls -al
echo; echo
echo "Output of \"df\" command"
echo
df

# ----------------------------------------------------------- #

exec 1>&6 6>&- # Restore stdout and close file descriptor #6.

echo
echo "== stdout now restored to default == "
echo
ls -al
echo

exit 0

appears to show what you want. It came from the ABS, where there is a small amount of discussion and other relevant information.

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

How to redirect stdout to a file and then restore stdout back?

You need to check the return values of your function calls. For most functions, you should check for error conditions. Doing so might have revealed the problem that if you want open() to create the requested file in the event that it does not initially exist, then you need to add the O_CREAT flag.

But that's not your main problem here -- you are dealing with a buffering issue. The output from the first printf() is buffered in memory, so even though file descriptor 1 refers to your file at the time that printf() is called, the data you write do not immediately get flushed to the destination file. You then restore the original stdout file handle, so when the data are actually flushed, they go to the (restored) original stdout. Solve this by fflush()ing before switching stdout back:

int pfd = open("file", O_WRONLY | O_CREAT, 0777);
int saved = dup(1);

close(1);
dup(pfd);
close(pfd);
printf("This goes into file\n");
fflush(stdout); // <-- THIS

// restore it back
dup2(saved, 1);
close(saved);
printf("this goes to stdout");

Note also that dup2() is cleaner and safer for duping a file descriptor onto a specific file descriptor number. You do that when you restore, but you should also do it for the initial redirection.

Python: Revert sys.stdout to default

You can revert to the original stream by reassigning to sys.__stdout__.

From the docs

contain[s] the original values of stdin, stderr and stdout at the start of the program. They are used during finalization, and could be useful to print to the actual standard stream no matter if the sys.std* object has been redirected.

The redirect_stdout context manager may be used instead of manually reassigning:

import contextlib

with contextlib.redirect_stdout(myoutputfile):
print(output)

(there is a similar redirect_stderr)

Changing sys.stdout has a global effect. This may be undesirable in multi-threaded environments, for example. It might also be considered as over-engineering in simple scripts. A localised, alternative approach would be to pass the output stream to print via its file keyword argument:

print(output, file=myoutputfile) 

After using `exec 1 file`, how can I stop this redirection of the STDOUT to file and restore the normal operation of STDOUT?

Q1

You have to prepare for the recovery before you do the initial exec:

exec 3>&1 1>file

To recover the original standard output later:

exec 1>&3 3>&-

The first exec copies the original file descriptor 1 (standard output) to file descriptor 3, then redirects standard output to the named file. The second exec copies file descriptor 3 to standard output again, and then closes file descriptor 3.

Q2

This is a bit open ended. It can be described at a C code level or at the shell command line level.

exec 1>file

simply redirects the standard output (1) of the shell to the named file. File descriptor one now references the named file; any output written to standard output will go to the file. (Note that prompts in an interactive shell are written to standard error, not standard output.)

exec 1>&-

simply closes the standard output of the shell. Now there is no open file for standard output. Programs may get upset if they are run with no standard output.

Q3

If you close all three of standard input, standard output and standard error, an interactive shell will exit as you close standard input (because it will get EOF when it reads the next command). A shell script will continue running, but programs that it runs may get upset because they're guaranteed 3 open file channels — standard input, standard output, standard error — and when your shell runs them, if there is no other I/O redirection, then they do not get the file channels they were promised and all hell may break loose (and the only way you'll know is that the exit status of the command will probably not be zero — success).



Related Topics



Leave a reply



Submit