conditional redirection in bash

daniel kullmann picture daniel kullmann · Jan 6, 2012 · Viewed 7.7k times · Source

I have a bash script that I want to be quiet when run without attached tty (like from cron). I now was looking for a way to conditionally redirect output to /dev/null in a single line. This is an example of what I had in mind, but I will have many more commands that do output in the script

#!/bin/bash
# conditional-redirect.sh
if tty -s; then 
  REDIRECT=
else 
  REDIRECT=">& /dev/null"
fi
echo "is this visible?" $REDIRECT

Unfortunately, this does not work:

$ ./conditional-redirect.sh
is this visible?
$ echo "" | ./conditional-redirect.sh 
is this visible? >& /dev/null

what I don't want to do is duplicate all commands in a with-redirection or with-no-redirection variant:

if tty -s; then 
  echo "is this visible?"
else 
  echo "is this visible?" >& /dev/null
fi

EDIT:

It would be great if the solution would provide me a way to output something in "quiet" mode, e.g. when something is really wrong, I might want to get a notice from cron.

Answer

paxdiablo picture paxdiablo · Jan 6, 2012

For bash, you can use the line:

exec &>/dev/null

This will direct all stdout and stderr to /dev/null from that point on. It uses the non-argument version of exec.

Normally, something like exec xyzzy would replace the program in the current process with a new program but you can use this non-argument version to simply modify redirections while keeping the current program.

So, in your specific case, you could use something like:

tty -s
if [[ $? -eq 1 ]] ; then
    exec &>/dev/null
fi

If you want the majority of output to be discarded but still want to output some stuff, you can create a new file handle to do that. Something like:

tty -s
if [[ $? -eq 1 ]] ; then
  exec 3>&1 &>/dev/null
else 
  exec 3>&1
fi
echo Normal               # won't see this.
echo Failure >&3          # will see this.