Sams Teach Yourself Shell Programming in 24 Hours
(Publisher: Macmillan Computer Publishing)
Author(s): Sriranga Veeraraghavan
ISBN: 0672314819
Publication Date: 01/01/99

Previous Table of Contents Next


Hour 24
Shell Programming FAQs

Each of the previous chapters has focused on an individual topic in shell programming, such as variables, loops, or debugging. As you progressed through the book, you worked on problems that required knowledge from previous chapters. In this chapter, I’m taking a slightly different approach. I will try to answer some common shell programming questions that frequently arise. Specifically I will cover questions from three main areas of shell programming:

  The shell and commands
  Variables and arguments
  Files and directories

Each section includes several common questions (along with answers) that occur in shell programming. These questions are designed to help you solve or avoid problems while programming using the shell.

Some of the questions provide deeper background information about UNIX, whereas others illustrate concepts covered in previous chapters.

Shell and Command Questions

In this section I will cover some of the common questions that arise in regard to the shell itself. Also included are a few questions regarding the execution of commands.

Why does #!/bin/sh have to be the first line of my scripts?

In Chapter 2, “Script Basics,” I stated that #!/bin/sh must be the first line in your script to ensure that the correct shell is used to execute your script. This line must be the first line in your shell script because of the underlying mechanism used by a shell to execute commands.


When you ask a shell to execute the command $ date,the shell uses the system call exec to ask the UNIX kernel to execute the command you requested. For those readers who are not familiar with the term system call, a system call is a C language function built in to the UNIX kernel that enables you to access features of the kernel.

The shell passes the name of the command that should be executed to the exec system call. This system call reads the first two characters in a file to determine how to execute the command. In the case of shell scripts, the first two characters are #!, indicating that the script needs to be interpreted by another program instead of executed directly. The rest of the line is treated as the name of the interpreter to use.

Usually the interpreter is /bin/sh, but you can also specify options to the shell on this line. Sometimes options such as -x or -nv are specified to enable debugging. This also enables you to write scripts tuned for a particular shell such as ksh or bash by using /bin/ksh or /bin/bash instead of /bin/sh.

How can I access the name of the current shell in my initialization scripts?

In your shell initialization scripts, the name of the current shell is stored in the variable $0.

Users who have a single .profile that is shared by sh, ksh, and bash use this variable in conjunction with a case statement near the end of this file to execute additional shell specific startup.

For example, I use the following case statement near the end of my .profile to set up the prompt, PS1, differently depending on the shell I am using:

case "$0" in
    *bash) PS1="\t \h \#$ " ;;
    *ksh) PS1="`uname -n` !$ " ;;
    *sh) PS1="`uname -n`$ " ;;
esac
export PS1

I have specified the shells as *bash, *ksh, and *sh, because some versions of UNIX place the - character in front of login shells, but not in front of other shells.

How do I tell whether the current shell is interactive or noninteractive?

Some scripts will need the capability to determine whether they are running in an interactive shell or noninteractive shell.

Usually this is restricted to your shell initialization scripts because you don’t want to perform a full-blown initialization every time these scripts execute. Some other examples include scripts that can run from the at or cron commands.

Two common methods can determine whether a shell is interactive:

  test -t or [ -t ]
  tty -s

Both commands exit with zero status if STDIN is connected to a terminal. For example, the commands

$ if [ -t ] ; then echo interactive ; fi

and

$ if tty -s ; then echo interactive ; fi

produce the same result if the current shell is interactive:

interactive

On modern versions of UNIX both forms work equally well. On some older versions of UNIX the test -t command was not available, so the tty -s command had to be used.

How do I discard the output of a command?

Sometimes you will need to execute a command, but you don’t want the output displayed to the screen. In these cases you can discard the output by redirecting it to the file /dev/null:

command > /dev/null

Here command is the name of the command you want to execute. The file is a special file (called the bit bucket) that automatically discards all its input.

To discard both output of a command and its error output, use standard redirection to redirect STDERR to STDOUT:

command > /dev/null 2>&1

How can I display messages on STDERR?

You can display a message on to STDERR by redirecting STDIN into STDERR as follows:

echo message 1>&2

Here message is the message you want to display.

If you are interested in shell functions that perform additional formatting please consult Chapter 21, “Problem Solving with Functions,” which covers several shell functions that display messages on to STDERR.

How can I check whether a command was successful?

A command is successful if it exits with a status of zero. A nonzero exit code indicates that an error has occurred.

To check the exit code of the most recent command you executed, use the variable $?. For example:

grep root /etc/passwd > /dev/null 2>&1
if [ $? -ne 0 ] ; then echo "No one is in charge!" ; fi

Here you execute a grep command and then check the exit status of this command using the value stored in $?.


Previous Table of Contents Next