January 19, 2005, 11:34 AM — Send in your Unix questions today!
See additional Unix tips and tricks
If there's one thing that every Unix systems administrator knows, it's that there's always more than one way to get something done. Some ways of solving a problem are more efficient than others. Other ways of solving a problem are easier to understand or extend to similar, but not identical, situations. But there are always multiple solutions to a task.
In recent columns, we have looked at two very different methods of determining whether or not a script was being run interactively or through cron. In the first, we used the Solaris ptree command to determine the parentage (or "ancestry") of a task. If a process was started by crond or its parent process was started by crond, we would know that it was run through cron. In the second, we used the tty command to identify the controlling terminal. In fact, just knowing that there is a controlling terminal (such as /dev/ttyp1), we know a process is being run interactively; cron jobs do not have controlling terminals. In this third and last method, we will use a very simple conditional test, built into the shell, to determine whether a process is interactive. This simple test, -t, is in the same family of tests as -f (testing if there is a file with the specified name) and -d (testing if there is a directory with the specified name). The -t test determines whether the specified file descriptor is associated with a terminal. Let's look at a couple of examples to see how this works.
On the command line, we can use the -t test like this:
$ if [ -t 0 ]; then > echo interactive > fi interactive
Alternately, we can turn the command into a simple script. In this example, we're looking at a Bourne shell script, though this same syntax should work with bash and ksh. We are using the -t test to determine whether there is a terminal associated with file descriptor 0 (i.e., standard in). If there is an associated terminal, we print the message "interactive". If there is no associated terminal, we print "non-interactive".
#!/bin/sh # test0 if [ -t 0 ]; then echo interactive else echo non-interactive fi
Of course, what we need to do next is verify that we get the opposite response when we're not running our script interactively. To run this script through cron and verify that its output will be "non-interactive", we'll set up a cron task like this:
5 * * * * /export/home/shs/test0 > /var/log/test.log
Once the script runs, we should see the word "non-interactive" in our log file, basically demonstarting that standard in for a cron job is not associated with a terminal.
We could also run the same test using syntax like that shown below. While this syntax is more terse, it doesn't lend itself to executing a series of commands. Instead, it works better with single commands or function calls.
test -t 0 && echo "Running interactively" || echo "Running in batch"
Conditional Tests
Simple conditional tests, like -t, can be found in every Unix shell and on every "flavor" of Unix. While the set of such tests that is implemented may vary from system to system or shell to shell, there is enough overlap to make these tests extremely handy in any environment. Here is a list of some of the tests that you are likely to find extremely useful:
-b file, True if file exists and is a block special file. -c file, True if file exists and is a character special file. -d file, True if file exists and is a directory. -e file, True if file exists. -f file, True if file exists and is a regular file. -g file, True if file exists and is set-group-id. -h file, True if file exists and is a symbolic link. -k file, True if file exists and its ``sticky'' bit is set. -p file, True if file exists and is a named pipe (FIFO). -r file, True if file exists and is readable. -s file, True if file exists and has a size greater than zero. -t fd, True if file descriptor fd is open and refers to a terminal. -u file, True if file exists and its set-user-id bit is set. -w file, True if file exists and is writable. -x file, True if file exists and is executable.
The syntax for a conditional test is different in the C shell and tsch. In the sample script below, we've implemented the same simple test in csh:














