It can be useful at times to have a shell script behave differently if it's run interactively vs. run from cron or other non-interactive means. For example, you may want the script to send email on certain conditions if it's run from cron, but simply print the message to standard out if it's being run interactively.
Prerequisites:
o Familiarity with the bash shell
o Shell scripting experience |
One solution is to wrap the interactive cron with a non-interactive script. This generally isn't the best method as it requires duplicating code in two separate scripts and possibly creating hacked-together ways for the script to interact.
A better solution is to test if the shell is a tty or not.
Listing 1: Test if a shell is a TTY#!/bin/bash
tty -s
TTYTEST=$? |
$? is a special bash variable which means the return code of the most recent command, in this case "tty -s". Unix commands generally return 0 on success, and some number greater than 0 on failure. For "tty -s", a 0 (success) return code means the shell is a TTY, while anything other than 0 means the shell is
not. We can now use $TTYTEST to alter the behavior of our script.
Listing 2: Altering script flow based on TTY test#!/bin/bash
tty -s
TTYTEST=$?
# Random script code here, until we want to do something different based on TTY
if [ $TTYTEST -gt 0 ]; then
# Code to run if shell is NOT a TTY
else
# Code to run if the shell IS a TTY
fi |
The "-s" option to the tty command tells it to run silently. If you don't specify -s the tty command will print your TTY to standard out if you have one, or "not a tty" if you do not. If you don't want to deal with return codes you can do the following, however personally I think assigning a variable to the return code of "tty -s" is a more elegant way of doing this.
Listing 3: Alternate method to avoid using return codes#!/bin/bash
TTYTEST=`tty`
# Random script code here, until we want to do something different based on TTY
if [ "$TTYTEST" = 'not a tty' ]; then
# Code to run if shell is NOT a TTY
else
# Code to run if the shell IS a TTY
fi |
Note that $TTYTEST must be put in quotes since it is a string. The above method can be simplified into a one-line check if you only need to know if the shell is a TTY or not for one if statement.
Listing 4: Quick one-liner to test if a shell is a TTY#!/bin/bash
if [ "`tty`" = 'not a tty' ]; then
# Code to run if shell is NOT a TTY
else
# Code to run if the shell IS a TTY
fi |
Just as the $TTYEST variable had to be put in quotes since it was a string, so must `tty` when ran explicitly. Since `tty` will return a string, this must be wrapped in quotes as "`tty`" for it to be used.
#!/bin/bash
if tty -s ; then
# Code to run if shell IS a TTY
else
# Code to run if the shell IS NOT a TTY
fi
Thanks for pointing out a cleaner solution for one-offs than I provided. ;)