Bourne tutorial



Yüklə 478,18 Kb.
Pdf görüntüsü
səhifə14/20
tarix08.10.2017
ölçüsü478,18 Kb.
#3721
1   ...   10   11   12   13   14   15   16   17   ...   20

argument containing nothing. Therefore, "$@" can't possible work correctly. Yet it does. The reason is that

the shell considers the "$@" a special case. However, not all versions of the Bourne shell have the same

behavior. Some convert

"$@"


to

""

if no arguments are provided. For a general purpose wrapper program, this is wrong. The cat program would



complain that it cannot open the file provided, and would not print out the filename because there is one.

The fix for these systems is to use the pattern:

${1+"$@"}

To explain, if "$1" is defined, then replace this by "$@." If it is not defined, then do nothing. Therefore the

more portable form is:

/usr/local/$OS/$REV/$ARCH/bin/$CMD ${1+"$@"}

Status and Wasted Processes

There are two more flaws in the script: one minor and one major. The first is that the script creates a new

process unnecessarily. It's a small point, but if you want to optimize a commonly executed script, worthwhile.

The second problem is the script does not properly return the exit status. The fix is simple. Place exec before

the instruction:

exec /usr/local/$OS/$REV/$ARCH/bin/$CMD ${1+"$@"}

Normally, the shell creates a copy of itself for each line, and then executes the command on the line with the

new process. The exec command does the second step, without requiring the shell to copy itself. If the exec

command succeeds, the shell never executes the next line.

The second problem with the script is the exit status. The version without the "exec" script does not execute

the exit command. Therefore the exit status is zero. The one with the "exec" command never exits (unless the

program isn't found). Instead, the program it executes exits, and the exit status is passed to the script that

called the wrapper script. Why is this important? Well, the value of the status is the basis of flow control in

the Bourne shell.

Simple Flow Control

This is the other topic for this section. There are some subtle points, so bear with me. The simplest form is one

of these variations

command1 && command2

command1 || command2

As I have mentioned before, a program only has two ways to pass information to another process: a file/pipe,

Bourne Shell Tutorial

http://www.grymoire.com/Unix/Sh.html

38 of 66

11/21/2011 12:03 PM




or the exit status. A program cannot use environment variables to pass information back to the process that

created it. Most of the time a process does file I/O. The exit status is another quick and convenient method.

The status is an integer from 0 to 255. The shell can either examine the integer value of an exit status, or treat

the value as a boolean. Zero is true, all other values are false. If you do not provide an exit status, the system

returns with the status of the last command executed.

UNIX comes with two programs called true and false, which is simply the command "exit 0" and "exit 255."

Well, the true program doesn't even have an exit command. Since no commands are executed, the exit status

is zero. So, in essence, the true command does absolutely nothing, but takes nine lines, including the

copyright notice, to do nothing. I should warn you, however, that if you ever create a shell script that does

nothing, you risk the legal fury of the AT&T legal department for reverse engineering a program that took

untold hours to develop.

That's the scoop. Using the status gives you flow control. The "&&" is often called the "and" operator. It

executes the next command if the first command is true. The "||" operator is the "or" command, which

executes if the command is false. To illustrate:

true  && echo this line IS printed

false || echo this line IS printed

true  || echo this line is NOT printed

false && echo this line is NOT printed

Substitute the words "and" or "or" in the above examples, and read them quietly to yourself to understand

why. You can, if you wish, combine these operators one one line:

command && echo command succeeded || echo command failed

Allow me a brief discursion. The pipe character "|" is special. Several commands can be combined using pipes

into something called a pipeline. The shell has five different mechanisms to combine pipelines into a list. You

all know that the end of line character is one of the five. Here are examples of the other four:

cmd1 ; cmd2 ; cmd3 ; cmd4

cmd1 & cmd2 & cmd3 & cmd4

cmd1 && cmd2 && cmd3 && cmd4

cmd1 || cmd2 || cmd3 || cmd4

The semicolon tells the shell to operate sequentially. First "cmd1" is executed, then "cmd2," etc. Each

command starts up, and runs as long as they don't need input from the previous command. The "&" command

launches each process in a detached manner. The order is not sequential, and you should not assume that one

command finishes before the other. The last two examples, like the first, execute sequentially, as long as the

status is correct. In the "&&" example, "cmd4" is executed if all three earlier commands pass. In the "||"

example, "cmd4" is executed if the first three fail. The "&&" and "||" have higher precedence than ";" and

"&," but lower than "|." Therefore

a | b && c ; d || e | f ;

is evaluated as

(a | (b && c)) ; ((d || e) | f) ;

The || and && commands can be used for a simple if-then-else. Note that

cmd1 && cmd2 || cmd3

Bourne Shell Tutorial

http://www.grymoire.com/Unix/Sh.html

39 of 66

11/21/2011 12:03 PM




if cmd1 succeeds, and cmd2 fails, then cmd3 will be executed. To prevent this, one can use

cmd1 && {cmd2;exit 0; } || cmd3

Changing Precedence

If you want to change the precedence, or order of evaluation, you can use either curly braces or

parenthesis. There are some subtle differences between these two. Syntactically, there are two

differences:

(cmd1; cmd2) | cmd3

{ cmd1; cmd2; } | cmd3

Notice the semicolon at the end of the list in the curly brace. Also notice a space is required after the

first "{." There is another difference: the parenthesis causes the shell to execute a new process, while

the curly brace does not. You can set variables in a curly brace, and it will be known outside the braces.

In the example below, the first echo prints "OLD" and the second prints "NEW:"

a=OLD

(a=NEW) ; echo $a



{ a=NEW;} ; echo $a

Putting it all together

I've explained the pieces. Now I'll try to put everything together. If you want to temporarily ignore a

series of commands, without adding a "#" before each line, use the following:

false && {

command1


command2

command3


}

Change the false to true, and the commands get executed. Braces and parenthesis can be nested:

A && {

B && {


echo "A and B both passed"

} || {


echo "A passed, B failed"

}

} || echo "A failed"



The parenthesis and curly brace are useful when you want to merge standard output of multiple

commands. For instance, suppose you want to add a line containing "BEGIN" to the middle of a

pipeline, before the "C" command:

A | B | C | D

Bourne Shell Tutorial

http://www.grymoire.com/Unix/Sh.html

40 of 66

11/21/2011 12:03 PM




Yüklə 478,18 Kb.

Dostları ilə paylaş:
1   ...   10   11   12   13   14   15   16   17   ...   20




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©www.genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə