A.2 The if Statement


In this section, we begin looking at Bourne shell control structures: programming features seldom used on the command line. The first construct we will consider is if, used for conditional command execution. Here is the simplest syntax of an if statement and a simple if example:

if condition   then     commands   fi     if test -x /sbin/sendmail ; then     /sbin/sendmail $SENDMAIL_OPTIONS fi

The if command runs the commands in condition. If they return a true value (zero exit status), the commands are executed; on a false, nonzero status, the script jumps to the command after fi.

The preceding example uses the test command to check for the file /sbin/sendmail and starts the daemon if it's present and executable. We'll look at constructing conditions more closely a little later. For now, notice the placement of the then command. then must appear to the shell as a separate command, or you'll get an error. So it must be on a new line after the if command, or it must be separated from the if command by a semicolon. The same rules hold true for the fi command that ends the if construct.

There are more complex forms of if:

strings /vmunix | grep Unix > /tmp/motd  i=`head -1 /etc/motd | grep -c Unix`  if [ $i -eq 0 ]  then     cat /etc/motd >>/tmp/motd  else     tail +2 /etc/motd >>/tmp/motd  fi  mv /tmp/motd /etc/motd

This example illustrates the if-then-else construct. It updates the Unix version string in the message-of-the-day file. First, it gets the current Unix version string out of the kernel file /vmunix and puts it in the file /tmp/motd. Then, it checks whether the string "Unix" appears in the first line of /etc/motd. If it doesn't, the entire contents of /etc/motd are appended to /tmp/motd by the tail command. Otherwise when "Unix" does appear in the first line of /etc/motd all but its first two lines are appended to /tmp/motd. Finally, the new message file replaces the current one.

Here is an example of the most complex form of if:

set `who -r`                           Determine previous run level.  if [ "$9" = "S" ]                      Previous level was single-user mode.  then     echo "The system is coming up."  elif [ "$7" = "2" ]; then              Target  run level is level 2.     echo "Changing to state 2."  else     echo "Changing to state 3."  fi

The elif command allows if statements to be chained together. It functions as an else for the current if and as the beginning of a new if. The final else covers the case of all false conditions and ends the entire chain.

A.2.1 The test Command (a.k.a. [ )

The most common way to construct a condition for an if command is with the test command. It has two forms:

test condition  [ condition ]

test evaluates condition and returns 0 or 1, depending on whether the condition is true (0) or false (1). (This polarity matches up with if's sense of true and false.)

The open bracket ([) command is a link to test and works in exactly the same way. It makes for more readable scripts, so you'll seldom see test. If the [ form is used, a final closed bracket (]) is included to keep test from complaining. Note that there must be spaces after [ and before ].

Table A-2 lists the various options and operators that may be used to construct conditions with test and [.

Table A-2. Constructing conditions

Construct

Meaning

-s file

File has greater than 0 length.

-r file

File is readable.

-w file

File is writable.

-x file

File/directory is executable.

-f file

File exists and is a regular file.

-d file

File is a directory.

-c file

File is a character special file.

-b file

File is a block special file.

-p file

File is a named pipe.

-u file

File has SETUID bit set.

-g file

File has SETGID bit set.

-k file

File has sticky bit set.

-t n

File descriptor n refers to a terminal.

-e file

File exists.

-O file[a]

You own the file.

-Gfile[a]

Your group owns the file.

-L file[a]

File is a symbolic link.

-S file[a]

File is a socket.

-N file[a]

File has been modified since it was last read.

file1 -effile2[a]

Files reside on the same device and refer to the same inode number.

file1 -otfile2[a]

First file is older than second file.

file1 -ntfile2[a]

First file is newer than second file.

-z string

String's length is 0.

-n string

String's length is greater than 0.

string1 =string2

The two strings are identical.

string1 !=string2

The two strings are different.

string

String is not null.

string1>string2[a]

First string is lexically before second string.

string1<string2[a]

First string is lexically after second string.

int1-eq int2

The two integers are equal.

int1 -ne int2

The two integers are not equal.

int1 -gt int2

int1 is greater than int2.

int1 -ge int2

int1 is greater than or equal to int2.

int1 -lt int2

int1 is less than int2.

int1 -le int2

int1 is less than or equal to int2.

! condition

NOT logical operator: negates the condition.

cond1 -a cond2

AND logical operator: returns true only if both conditions are true.

cond1 -o cond2

OR logical operator: returns true if either condition is true.

( )

Used for grouping conditions.

[a] This item is an extension available in only some shell implementations.

Many of the items in Table A-2 require quoting to protect them from the shell (as we'll see).

Here are some simple examples:

if [ "$9" = "S" ]             If the 9th argument is S if [ -s /etc/ptmp ]           If /etc/ptmp is not empty if [ $# -lt 4 ]               If the number of arguments is  < 4 if [ ! -f /etc/.fsckask ]     If the plain file /etc/.fcskask does not exist if [ $? -eq 0 ]               If the last command succeeded if [ $? -ne 0 ]               If the last command failed

Here are some examples placed in context:

# get pid of lpsched pid=`/bin/ps -e | grep ' lpsched$' | sed -e 's/^ *//' -e 's/ .*//'` if [ $(pid) != "" ]           If we found an lpsched process ... then    /bin/kill $(pid)           ... kill it. fi if [ $lx = autobootx ]        If script  argument was "autoboot",    run fsck fi    if [ -d /etc/rc0.d ]          If there is a directory named /etc/rc0.d then    run the K files fi    if [ -x /sbin/inetd ]; then   If the file /sbin/inetd is executable . . .     /sbin/inetd                 . . . start the daemon    echo inetd started fi    if [ "$(BOOT)" = "yes" -a -d /etc/rc0.d ] then                          If this is a boot and there is an rc0.d directory    Run the files in /etc/rc0.d fi

Note that constructs such as the following are used to prevent errors from occurring when a script's expected argument turns out to be null:

if [ $lx = autobootx ]

There are, of course, other ways of handling this contingency, but this approach is quite common in system scripts, especially older ones.

Here's a tricky one; try to figure out what this does:

interface_names="`echo /etc/dhcp.*[0-9] 2>/dev/null`" if [ "$interface_names" != '/etc/dhcp.*[0-9]' ]; then   Configure the network interfaces with DHCP fi

A common mistake to make is to think the interface_name must always be the same as the filename string. The key here is to notice that the second operand to the not-equal operator in the if condition is a literal value: specifically, a string of characters and not a wildcarded filename. If there are any files of the form dhcp.xxxn in /etc (where xxx is a string and n is a number), the echo command returns the list of filenames. Otherwise, the literal string "/etc/dhcp.*[0-9]" is returned and becomes the value of interface_names.

The if command figures out which of these has happened. If interface_names has any value other than the literal wildcard string, the variable can be assumed to contain a list of filenames to be processed. On the other hand, if the variable holds only the wildcard string, then no files were found, and nothing needs to be done, so the commands in the body of the if block are skipped.



Essential System Administration
Essential System Administration, Third Edition
ISBN: 0596003439
EAN: 2147483647
Year: 2002
Pages: 162

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net