18

I would like to test in my bash script where stdout and stderr are directed, or more precisely, if they have been redirected.

Have you an idea ?

The $* bash variable don't give me this info.

2 Answers 2

26

Technically there is no way of telling whether stdin/stdout/stderr are "redirected" because you don't know what's invoking your script. If it's not being invoked from another shell, there is no concept of "redirection".

All you have to go on is what types the in/out/err file descriptors are (terminal, fifo, pipe, device, file etc). Normally you just want to detect whether your output is going to some user's screen or whether it's going to another process. In this case use [ -t 1 ] as per Mat's answer.

If you want to find out where/what your process has been redirected to, examine the targets of the symlinks /proc/$$/fd/1 and /proc/$$/fd/2.

Note that someone could connect the output of your process to a different terminal with ./myscript.sh > /dev/pts/1234. Then it would be "redirected", but stdout would still be a terminal.

Examples:

$ ls -l /proc/$$/fd/1 > results
$ bash -c 'ls -l /proc/$$/fd/1 >>results' > /dev/null
$ bash -c 'ls -l /proc/$$/fd/1 >>results' |cat 
$ bash -c 'ls -l /proc/$$/fd/1 >>results' > /dev/pts/0
$ cat results 
lrwx------ 1 je4d je4d 64 2012-02-17 21:09 /proc/2463/fd/1 -> /dev/pts/11
l-wx------ 1 je4d je4d 64 2012-02-18 13:17 /proc/8302/fd/1 -> /dev/null
l-wx------ 1 je4d je4d 64 2012-02-18 13:17 /proc/8304/fd/1 -> pipe:[222798]
l-wx------ 1 je4d je4d 64 2012-02-18 13:17 /proc/8307/fd/1 -> /dev/pts/0

[ -t 1 ] would be true for the 1st and 4th of those.

Sign up to request clarification or add additional context in comments.

3 Comments

This is a rich answer which allows me to understand some bash stuff. Thanks !
Thx! I did a command line test, but it did not work for my surprise. This command: ( lsof -p $$; ls -l /proc/$$/fd;[ -t 1 ] || echo -n NOT\ ;echo TERM:$$;ps --forest -s $$;)|cat - prints /dev/pts/1 for fd 1, but prints NOT TERM. So bash knows that it is redirected ((...) run in a sub-bash), but $$ is still the PID of the parent bash.
Yeah, that's just what $$ does, subshells don't affect it. That's why I used bash -c '...' instead.
25

You should be able to use the -t test switch to tell if the output streams are ttys or not:

if [ -t 1 ] ; then
  echo stdout is a terminal
else
  echo stdout is not a terminal
fi

Use -t 0 for stdin.

Use -t 2 for stderr.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.