12

Is it possible, within a shell script, to write to the screen while STDOUT and STDERR is being redirected?

I have a shell script that I want to capture STDOUT and STDERR. The script will run for perhaps an hour or more, so I want to occasionally write some status messages to the screen that will be displayed and not redirected (not captured).

For a minimal example, I have a shell script, let's say "./myscript.sh":

#!/bin/sh -u

echo "Message A: This writes to STDOUT or wherever '1>' redirects to."
echo "Message B: This writes to STDOUT or wherever '1>' redirects to.">&1
echo "Message C: This writes to STDERR or wherever '2>' redirects to.">/dev/stderr
echo "Message D: This writes to STDERR or wherever '2>' redirects to.">&2
echo "Message E: Write this to 'screen' regardless of (overriding) redirection." #>???  


Then, for example, I'd like to see this output when I run the script like this:

[~]# ./myscript.sh > fileout 2> filerr
Message E: Write this to 'screen' regardless of (overriding) redirection.
[~]# ./myscript.sh > /dev/null 2>&1
Message E: Write this to 'screen' regardless of (overriding) redirection.
[~]#    


If this cannot be done "directly", is it possible to temporarily discontinue redirection, then print something to the screen, then restore redirection as it was?

Some info about the computer:

[~]# uname -srvmpio
Linux 3.2.45 #4 SMP Wed May 15 19:43:53 CDT 2013 x86_64 x86_64 x86_64 GNU/Linux

[~]# ls -l /bin/sh /dev/stdout /dev/stderr
lrwxrwxrwx 1 root root  4 Jul 18 23:18 /bin/sh -> bash
lrwxrwxrwx 1 root root 15 Jun 29  2013 /dev/stderr -> /proc/self/fd/2
lrwxrwxrwx 1 root root 15 Jun 29  2013 /dev/stdout -> /proc/self/fd/1
3
  • 1
    echo msg > /dev/tty Jan 4, 2014 at 20:35
  • @strugee - I wanted to tag it with the OS: "GNU/Linux" but I wasn't allowed to (I even tried "GNU-Linux"), so I tagged as "GNU" and "Linux" individually. Jan 6, 2014 at 14:44
  • @StephaneChazelas - echo msg > /dev/tty. That worked! I was sure I tried this early on without success but I must have just tried other similar things. In any case it's working for me. If you'd like to put this as an answer, I'll mark it as accepted. Jan 22, 2014 at 17:50

3 Answers 3

6

Try a script like this:

#!/bin/bash
echo "to fd1" >&1
echo "to fd2" >&2
echo "to screen" >$(tty)

When you call it, it looks like this:

user@host:~# ./script
to fd1
to fd2
to screen
user@host:~# ./script 1>/dev/null
to fd2
to screen
user@host:~# ./script 2>/dev/null
to fd1
to screen
user@host:~# ./script > /dev/null 2>&1
to screen
1
  • >/dev/tty is better than >$(tty) because it works even if stdin is redirected and it doesn't have to go through the dance of attempting to scan around in /dev until the correct device is found.
    – Celada
    Jan 23, 2015 at 5:23
4

i don't know about all the tty redirection, but this is what I do:

Don't actually redirect, but send the output you want as a parameter or, if you are redirecting in the script itself, you can switch redirection at any time by executing:

exec 2> /some/new/destination 1> /some/other/destination

but you might want to save the old ones...

exec  3>&1 4>&2 2> /some/new/destination 1> /some/other/destination

that way you can come back to it... when you are done, or want to write to the screen

write to screen: echo "message" 1>&3

or..

all done: exec 1>&3 2>&4 # everything goes back to normal :)

0

Using the example from the answer by chaos:

echo "to screen" >$(tty)

did not work for me. I get an error when attempting to use it:

./myscript.sh: line xx: /dev/pts/3: Permission denied

I came up with a solution to use another file descriptor (9). Here is "./myscript.sh":

#!/bin/sh -u

## This is placed one time at the top of the script  
## to detect if file descriptor (9) is available for writing.
if [ ! -t 3 ]; then
    echo "Error, file descriptor (9) not open on terminal." >&2
    echo "" >&2
    if [ ! -t 2 ]; then
        echo "Error, file descriptor (9) not open on terminal."
        echo ""
    fi
    exit 1
fi

echo "Message A: This writes to stdout or wherever '1>' redirects to."
echo "Message B: This writes to stdout or wherever '1>' redirects to.">&1
echo "Message C: This writes to stderr or wherever '2>' redirects to.">/dev/stderr
echo "Message D: This writes to stderr or wherever '2>' redirects to.">&2
echo "Message E: Write this to 'screen' regardless of '1>/2>' redirection." >&9
echo " " >&9

I used file descriptor 9 to output the "status" messages to, but other valid file descriptors should work.

To use it, when calling the script, you have to include redirection of file descriptor (9) to STDOUT (9>&1) as the first redirection.

Here is the output when I call "./myscript.sh":

[~]# ./myscript.sh
[~]# ./myscript.sh >/dev/null
[~]# ./myscript.sh 2>/dev/null
Error, file descriptor (9) not open on terminal.

[~]# ./myscript.sh >/dev/null 9>&1
Error, file descriptor (9) not open on terminal.

[~]# ./myscript.sh 9>&1 >/dev/null
Message C: This writes to stderr or wherever '2>' redirects to.
Message D: This writes to stderr or wherever '2>' redirects to.
Message E: Write this to 'screen' regardless of '1>/2>' redirection.

[~]# ./myscript.sh 9>&1 2>/dev/null
Message A: This writes to stdout or wherever '1>' redirects to.
Message B: This writes to stdout or wherever '1>' redirects to.
Message E: Write this to 'screen' regardless of '1>/2>' redirection.

[~]# ./myscript.sh 9>&1 >/dev/null 2>&1
[~]# ./myscript.sh 9>&1 &>/dev/null
[~]# ./myscript.sh 9>&1 >&/dev/null
Message E: Write this to 'screen' regardless of '1>/2>' redirection.

[~]#

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .