📄 unx11.htm
字号:
<P>The results of the preceding expression may seem odd. The first thing to remember is that division and multiplication are of a higher precedence than addition and subtraction, so the first operation performed is 7 divided by 3. Because expr deals only
in integers, the result of the division is 2, which is then added to 5, giving the final result 7. Parentheses are not recognized by expr, so to override the precedence, you must do that manually. You can use back quotation marks to change the precedence,
as follows:
<BR></P>
<PRE>$ int='expr 5 + 7'
$ expr $int / 3
4</PRE>
<P>Or you can use the more direct route:
<BR></P>
<PRE>$ expr 'expr 5 + 7' / 3
4</PRE>
<H4 ALIGN="CENTER">
<CENTER><A ID="I36" NAME="I36">
<FONT SIZE=3><B>Passing Arguments to Shell Programs</B>
<BR></FONT></A></CENTER></H4>
<P>A program can get data in two ways: either it is passed to the program when it is executed as arguments, or the program gets data interactively. An editor such as vi is usually used in an interactive mode, whereas commands such as ls and expr get their
data as arguments. Shell programs are no exception. In the section "Reading Data into a Program Interactively," you see how a shell program can get its data interactively.
<BR></P>
<P>Passing arguments to a shell program on a command line can greatly enhance the program's versatility. Consider the inverse of the backup program presented earlier:
<BR></P>
<PRE>$ cat >restoreall
cd $WORKDIR
cpio -i </dev/rmt0
Ctrl+d</PRE>
<P>As written, the program restoreall reloads the entire tape made by backup. But what if you want to restore only a single file from the tape? You can do so by passing the name of the file as an argument. The enhanced restore1 program is now:
<BR></P>
<PRE># restore1 - program to restore a single file
cd $WORKDIR
cpio -i $1 </dev/rmt0</PRE>
<P>Now you can pass a parameter representing the name of the file to be restored to the restore1 program:
<BR></P>
<PRE>$ restore1 file1</PRE>
<P>Here, the filename file1 is passed to restore1 as the first positional parameter. The limitation to restore1 is that if you want to restore two files, you must run restore1 twice.
<BR></P>
<P>As a final enhancement, you can use the $* variable to pass any number of arguments to the program:
<BR></P>
<PRE># restoreany - program to restore any number of files
cd $WORKDIR
cpio -i $* </dev/rmt0
$ restoreany file1 file2 file3</PRE>
<P>Because shell variables that have not been assigned a value always return null, or empty, if the restore1 or restoreany programs are run with no command-line parameters, a null value is placed in the cpio command, which causes the entire archive to be
restored.
<BR></P>
<P>Consider the program in listing 11.1; it calculates the length of time to travel a certain distance.
<BR></P>
<UL>
<LH><B>Listing 11.1. Program example with two parameters.</B></LH></UL>
<PRE># traveltime - a program to calculate how long it will
# take to travel a fixed distance
# syntax: traveltime miles mph
X60='expr $1 \* 60'
TOTMINUTES='expr $X60 / $2'
HOURS='expr $TOTMINUTES / 60'
MINUTES='expr $TOTMINUTES % 60'
echo "The trip will take $HOURS hours and $MINUTES minutes"</PRE>
<P>The program in listing 11.1 takes two positional parameters: the distance in miles and the rate of travel in miles per hour. The mileage is passed to the program as $1 and the rate of travel as $2. Note that the first command in the program multiplies
the mileage by 60. Because the expr command works only with integers, it is useful to calculate the travel time in minutes. The user-defined variable X60 holds an interim calculation that, when divided by the mileage rate, gives the total travel time in
minutes. Then, using both integer division and modulus division, the number of hours and number of minutes of travel time is found.
<BR></P>
<P>Now execute the traveltime for a 90-mile trip at 40 mph with the following command line:
<BR></P>
<PRE>$ traveltime 90 40
The trip will take 2 hours and 15 minutes</PRE>
<H4 ALIGN="CENTER">
<CENTER><A ID="I37" NAME="I37">
<FONT SIZE=3><B>Decision Making in Shell Programs</B>
<BR></FONT></A></CENTER></H4>
<P>One of the things that gives computer programming languages much of their strength is their capability to make decisions. Of course, computers don't think, so the decisions that computer programs make are only in response to conditions that you have
anticipated in your program. The decision making done by computer programs is in the form of conditional execution: if a condition exists, then execute a certain set of commands. In most computer languages, this setup is called an if-then construct.
<BR></P>
<H5 ALIGN="CENTER">
<CENTER><A ID="I38" NAME="I38">
<FONT SIZE=3><B>The </B><B><I>if-then</I></B><B> Statement</B>
<BR></FONT></A></CENTER></H5>
<P>The Bourne shell also has an if-then construct. The syntax of the construct is as follows:
<BR></P>
<PRE>if command_1
then
command_2
command_3
fi
command_4</PRE>
<P>You may recall that every program or command concludes by returning an exit status. The exit status is available in the shell variable $?. The if statement checks the exit status of its command. If that command is successful, then all the commands
between the then statement and the fi statement are executed. In this program sequence, <I>command_1</I> is always executed, <I>command_2</I> and <I>command_3</I> are executed only if <I>command_1</I> is successful, and <I>command_4</I> is always executed.
<BR></P>
<P>Consider a variation of the backup program, except that after copying all the files to the backup media, you want to remove them from your disk. Call the program unload and allow the user to specify the directory to be unloaded on the command line, as
in the following example:
<BR></P>
<PRE># unload - program to backup and remove files
# syntax - unload directory
cd $1
ls -a | cpio -o >/dev/rmt0
rm *</PRE>
<P>At first glance, it appears that this program will do exactly what you want. But what if something goes wrong during the cpio command? In this case, the backup media is a tape device. What if the operator forgets to insert a blank tape in the tape
drive? The rm command would go ahead and execute, wiping out the directory before it has been backed up! The if-then construct prevents this catastrophe from happening. A revised unload program is shown in listing 11.2.
<BR></P>
<UL>
<LH><B>Listing 11.2. Shell program with error checking.</B></LH></UL>
<PRE># unload - program to backup and remove files
# syntax - unload directory
cd $1
if ls -a | cpio -o >/dev/rmt0
then
rm *
fi</PRE>
<P>In the program in listing 11.2, the rm command is executed only if the cpio command is successful. Note that the if statement looks at the exit status of the last command in a pipeline.
<BR></P>
<H5 ALIGN="CENTER">
<CENTER><A ID="I39" NAME="I39">
<FONT SIZE=3><B>Data Output from Shell Programs</B>
<BR></FONT></A></CENTER></H5>
<P>The standard output and error output of any commands within a shell program are passed on the standard output of the user who invokes the program unless that output is redirected within the program. In the example in listing 11.2, any error messages
from cpio would have been seen by the user of the program. Sometimes you may write programs that need to communicate with the user of the program. In Bourne shell programs, you usually do so by using the echo command. As the name indicates, echo simply
sends its arguments to the standard output and appends a newline character at the end, as in the following example:
<BR></P>
<PRE>$ echo "Mary had a little lamb"
Mary had a little lamb</PRE>
<P>The echo command recognizes several special escape characters that assist in formatting output. They are as follows:
<BR></P>
<PRE>
<BR>\b Backspace
<BR>\c Prints line without newline character
<BR>\f Form Feed: advances page on a hard copy printer; advances to new screen on a display terminal
<BR>\n Newline
<BR>\r Carriage return
<BR>\t Tab
<BR>\v Vertical Tab
<BR>\\ Backslash
<BR>\0nnn A one-, two-, or three-digit octal integer representing one of the ASCII characters</PRE>
<P>If you want to display a prompt to the user to enter the data, and you want the user response to appear on the same line as the prompt, you use the \c character, as follows:
<BR></P>
<PRE>$ echo "Enter response:\c"
Enter response$</PRE>
<H5 ALIGN="CENTER">
<CENTER><A ID="I40" NAME="I40">
<FONT SIZE=3><B>The </B><B><I>if-then-else</I></B><B> Statement</B>
<BR></FONT></A></CENTER></H5>
<P>A common desire in programming is to perform one set of commands if a condition is true and a different set of commands if the condition is false. In the Bourne shell, you can achieve this effect by using the if-then-else construct:
<BR></P>
<PRE>if command_1
then
command_2
command_3
else
command_4
command_5
fi</PRE>
<P>In this construct, <I>command_1</I> is always executed. If <I>command_1</I> succeeds, the <I>command_2</I> and <I>command_3</I> are executed; if it fails, <I>command_4</I> and <I>command_5</I> are executed.
<BR></P>
<P>You can now enhance the unload program to be more user friendly. For example,
<BR></P>
<PRE># unload - program to backup and remove files
# syntax - unload directory
cd $1
if ls -a | cpio -o >/dev/rmt0
then
rm *
else
echo "A problem has occurred in creating the backup."
echo "The directory will not be erased."
echo "Please check the backup device and try again."
fi</PRE>
<HR ALIGN=CENTER>
<NOTE>
<IMG SRC="imp.gif" WIDTH = 68 HEIGHT = 35><B>TIP:</B> Because the shell ignores extra whitespace in a command line, good programmers use this fact to enhance the readability of their programs. When commands are executed within a then or else clause, indent
all the commands in the clause the same distance.
<BR></NOTE>
<HR ALIGN=CENTER>
<H5 ALIGN="CENTER">
<CENTER><A ID="I41" NAME="I41">
<FONT SIZE=3><B>Testing Conditions with </B><B><I>test</I></B>
<BR></FONT></A></CENTER></H5>
<P>You've seen how the if statement tests the exit status of its command to control the order in which commands are executed, but what if you want to test other conditions? A command that is used a great deal in shell programs is the test command. The test
command examines some condition and returns a zero exit status if the condition is true and a nonzero exit status if the condition is false. This capability gives the if statement in the Bourne shell the same power as other languages with some enhancements
that are helpful in shell programming.
<BR></P>
<P>The general form of the command is as follows:
<BR></P>
<PRE>test condition</PRE>
<P>The conditions that can be tested fall into four categories: 1) String operators that test the condition or relationship of character strings; 2) Integer relationships that test the numerical relationship of two integers; 3) File operators that test for
the existence or state of a file; 4) Logical operators that allow for and/or combinations of the other conditions.
<BR></P>
<H5 ALIGN="CENTER">
<CENTER><A ID="I42" NAME="I42">
<FONT SIZE=3><B>Testing Character Data</B>
<BR></FONT></A></CENTER></H5>
<P>You learned earlier that the Bourne shell does not type cast data elements. Each word of an input line and each variable can be taken as a string of characters. Some commands, such as expr and test, have the capability to perform numeric operations on
strings that can be translated to integer values, but any data element can be operated on as a character string.
<BR></P>
<P>You can compare two strings to see whether they are equivalent or not equivalent. You also can test a single string to see whether it has a value or not. The string operators are as follows:
<BR></P>
<TABLE BORDER>
<TR>
<TD>
<P>str1 = str2</P>
<TD>
<P>True if str1 is the same length and contains the same characters as str2</P>
<TR>
<TD>
<P>str1 != str2</P>
<TD>
<P>True if str1 is not the same as str2</P>
<TR>
<TD>
<P>-n str1</P>
<TD>
<P>True if the length of str1 is greater than 0 (is not null)</P>
<TR>
<TD>
<P>-z str1</P>
<TD>
<P>True if str1 is null (has a length of 0)</P>
<TR>
<TD>
<P><I>str1</I></P>
<TD>
<P>True if <I>str1</I> is not null</P></TABLE>
<P>Even though you most often use test with a shell program as a decision maker, test is a program that can sta
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -