Detecting Interactive shells in bash
I was recently tasked with writing a bash shell script that behaved differently depending on if it was invoked interactively (by a user at the command line), or non-interactively (cron).
There are surprisingly few useful results returned by Google. Both the “Advanced Bash-Scripting Guide” and GNU Bash manual mention testing to see if the prompt variable is set:
if [ -z $PS1 ]
but that will not work. For one thing, it’s perfectly reasonable for someone to have their prompt set to null, but aside from that, the prompt variables are not set when invoking a script so the test always returns the same result.
A coworker pointed out that that strangely, “man bash” has other ideas. In the Conditional Expressions section, it explains “-t fd True if file descriptor fd is open and refers to a terminal.” That sounds exactly like what we want:
if [[ -t 0 ]] ; then echo interactive else echo non-interactive fi
but there is still a problem. If you invoke the script remotely via an ssh call (e.g. ssh root@<remotehost> bashscript.sh”), stdin will not be connected to a terminal. To make the command more reliable we need one more test:
if [[ -t 0 || -S /dev/stdin ]] ; then echo interactive else echo non-interactive fi
Be aware that detecting a socket is also no proof of “interactivity”, but at least we are getting closer.