Thursday, 7 February 2013

Pipeline filter to allow changing stdout of a process while it is still running

On a Unix-style system, running processes write characters to a location called the standard output. By default, these will appear on a terminal, as text for the user to see. However, it's possible to redirect the standard output to a file, or to be the input for another process.

It may occasionally be useful to be able to redirect the standard output after a process has already started. I'm sure that others have done similar things before, but I couldn't find exactly what I was looking for.

For this purpose, I wrote the following bash script, saved as "MovableStdout.sh":

new_stdout_pipe=~/ChangeTerminal

redirect () {
        read new_stdout <$new_stdout_pipe
        exec >$new_stdout
}

trap redirect SIGUSR1

while true; do
        if ! read line; then
                exit;
        fi
        echo $line
done

To use this, a named pipe (a FIFO) must be created, e.g. by running "mkfifo ~/ChangeTerminal". This pipe will be used to communicate with the running script.

Use it by running

$ program | bash MovableStdout.sh

The program will run and the script will copy the stdout from the program to the terminal.

If we later wish to change where what is written to stdout goes, we may do this in a two step process. For example, if we are in another terminal, and wish to divert the output to the current terminal, we may do:
$ echo `tty` >~/ChangeTerminal &
$ ps -C bash
TT       USER       PID COMMAND
tty2     root      1457 -bash
pts/0    g         1875 /bin/bash
pts/1    g         2638 /bin/bash
pts/2    g         3117 /bin/bash
pts/3    g         3774 /bin/bash
pts/4    g         3150 /bin/bash
pts/5    g         3162 /bin/bash
pts/6    g         3808 /bin/bash
pts/7    g         3937 /bin/bash
pts/7    g         3950 bash MovableStdout.sh
$ kill -USR1 3950
(The exact processes listed will obviously be different.) The new output file name is placed onto the pipe, and then the script is signalled to read the file name from the pipe. The script catches this signal and redirects its output to the new file.

A limitation of this script is that you can only have one running instance of it at a time, otherwise you will have multiple running scripts trying to read from the same pipe. However, it could easily be altered to, for example, read the name of the pipe as a command-line parameter.

I was able to use this script to redirect the error messages from my X11 window manager to an xterm window.

No comments:

Post a Comment