• Aucun résultat trouvé

The All-Important If,Then, and Else

Dans le document Register for Free Membership to (Page 137-143)

The lists which utilized the &&and || character combinations are nice for one-shot program control, but nothing beats if-then-elsestatements, or in bash-speak,if-then-elif. Here is a simple parameter checking example:

j0pb12:~ johnnylong$ cat foo if [ $# -eq 0 ]; then

echo "Give me at least one parameter."

elif [ $# -eq 1 ]; then Give me at least one parameter.

j0pb12:~ johnnylong$ ./foo 1 OK, give me two.

Note the use of spaces around the [ ].These must exist or the test will produce an error.The ifstatement tests the return code of the teststatement, and if it evaluates as true, will execute the line or lines following the first then statement. If the statement evaluates as false, the script continues to the elif, which is shorthand for else, if. If the else, if statement evaluates as true, the pro-gram will execute the line or lines following the thenstatement. If both the if and elif statements evaluate as false, the else statement is executed.There can be multiple elif statements, but there can only be one else statement, which should be the last selection before the fi, which marks the end of the if clause.

Loops

There are quite a few different loops, and they are all robust. We take a look at the most basic implementations of both for,while, and until.The first use of for operates on a provided list of words. Consider the following example:

j0pb12:~/temp johnnylong$ cat for_list for i in "abc" "def"; do

echo $i done

j0pb12:~/temp johnnylong$ ./for_list abc

def

This script runs through the for loop twice, each time assigning a value to the $i variable.The first time through the loop,$i is set to abc, and the second time through the loop,$i is set to def. Each time through the loop, the con-tent of the $ivariable is printed to the screen with the echo $i command.

There is a different way to produce the same results in a potentially more powerful way:

This script assigns abc and def to variable $i and writes it to the screen, with the exact same results as the first example.There’s a specific convention used here(not yet discussed), but it is very powerful; the use of the grave (`) symbol.This symbol, which is located below the esc key and to the left of the 1key on most Mac keyboards, triggers the launch of a subshell. Once the command enclosed in graves is executed, the output of that command is sent to the top-level shell, where that output is operated on, one space-delimited word at a time. Put another way, the output of the command in graves replaces the command itself in the script. For example, changing the sub-shell command to ls would send the output of the ls command through the for loop:

Notice that this example “fed” the output of the ls command through the forloop.The output of the ls command replaced the command itself in the script, one word at a time. Although this seems useless, a script like this can be easily modified to perform an action on each and every file:

j0pb12:~/temp johnnylong$ ls file1 file2 file3 poo

j0pb12:~/temp johnnylong$ cat file*

j0pb12:~/temp johnnylong$ cat poo

done

j0pb12:~/temp johnnylong$ ./poo

j0pb12:~/temp johnnylong$ cat file*

This file owned by a Mac Hacker This file owned by a Mac Hacker This file owned by a Mac Hacker

The local directory contains three files:file1,file2,file3, and poo.The first three files are empty and the file poocontains our script.The script runs the ls command, and runs each word output from the ls command through the for loop, assigning that word to the $i variable. If the name of the current file (held in $i) is not poo, the phrase “This file owned by a Mac Hacker” is appended to that file. We’ll use this technique later in this section.

Our for loop could be modified to operate on a sequence of numbers by changing the subshell command to something such as “echo 1 2 3,”or by pro-viding a for loop like for i in 1 2 3; do, but a second variation of the for loop accounts for this:

This script uses a different type of forloop, which accepts no more than three expressions.The first expression is run once, when the for loop is first executed.The second expression is analyzed each time it goes through the loop, to determine if the expression evaluates to false. If this expression returns false, then the for loop’s body is bypassed and control passed to the expression following the done marker.The third expression is executed each time the loop is executed. In our example script, the variable $i is first set to 1, and the second expression is evaluated. It is determined that $i is less than or equal to 3, so the body of the forloop is executed, echoing the value of $i.

Once the body of the loop is completed, the for loop increments $i by one,

and the loop repeats until $i is greater than 3, at which point control is passed to the donemarker, which is located at the end of this script.This loop

becomes even more powerful if more complex expressions are used, especially those which spawn subshells.

The while loop is also extremely useful, and is a bit more simple than the for loop. Consider this example:

A while loop will execute as long as the expression evaluates as true. In this example, the loop will run as long as $iis not equal to abc.The body of the while loop reads characters from the keyboard, assigning each to $i. As long as abc is not entered at the keyboard, the loop will continue to run. We can also emulate the behavior of a for loop, as long as we can increment a number.

Incrementing a number is fairly simple thanks to the letcommand:

j0pb12:~/temp johnnylong$ x=1

This example sets $xequal to 1, and displays it to the screen with the echo command.The letcommand is then used to set $xequal to the current value plus one. Notice that the second x in the let command does not use the $x reference. However, it probably should since setting a variable does not use the

$, but referencing a variable should use the $.The let command does not

while [ "$i" -le "3" ]; do

Notice that the $i variable must be set to a value first, and that it is incre-mented inside the loop with the let command.The while loop executes as long as the expression (in this case “$i” -l “3”) evaluates as true. Conversely, the until loop will execute as long as the leading expression evaluates as false.

Here’s what the simple counter script would look as an untilloop:

j0pb12:~/temp johnnylong$ cat until_loop

Notice that the $i variable is again defined before the loop is executed, and that it is incremented inside the loop.This is similar to the while loop, and unlike until loops in other programming languages, the expression is evaluated at the top of the loop.

Loops can also be nested, meaning they can run inside other loops:

j0pb12:~/temp johnnylong$ cat ./nested_loop for (( i=1; $i <= 3; i=i+1 )); do

echo "i: $i"

for (( x=1; $x <= 2; x=x+1 )); do echo " x: $x"

done done

j0pb12:~/temp johnnylong$ ./nested_loop i: 1

x: 1 x: 2 i: 2

x: 1 x: 2 i: 3

x: 1 x: 2

In this example,$i is incremented between increments of $x.This type of loop can be very powerful, especially if you keep track of all your variables.

Dans le document Register for Free Membership to (Page 137-143)