Annotation of 43BSDTahoe/new/help/src/cshell/flowcontrol, revision 1.1.1.1

1.1       root        1: .TI CSHELL/FLOWCONTROL
                      2: Control Statements:  Branching and Looping
                      3: 
                      4: 
                      5: In the C shell, control statements are special built-in commands
                      6: that you enter around or near conventional commands,
                      7: often on separate lines.
                      8: They let you tell the shell how to control the execution
                      9: of the commands they affect.
                     10: This means that instead of having the shell execute all your commands
                     11: one after another as it does normally,
                     12: you can have it skip some or repeat some.
                     13: This ability to skip or repeat commands, called branching and looping,
                     14: respectively, is more powerful than it might sound at first.
                     15: 
                     16: Branching control statements are truly useful only inside shell scripts,
                     17: where the shell reads and executes commands from a file
                     18: instead of from the terminal.
                     19: Inside the script they serve mainly to let you store several
                     20: different command sequences compactly,
                     21: specifying ahead of time on what basis you want the shell to
                     22: skip or choose certain statements while the script is running.
                     23: The basis for decisions made while the script is running
                     24: is usually furnished by such things as arguments given to the script,
                     25: the time of day, whether a certain file exists, etc.
                     26: You enter decision points using a special notation called expressions.
                     27: 
                     28: Looping control statements are useful both inside shell scripts
                     29: and when entered from the terminal.
                     30: Although they are used to execute commands repeatedly,
                     31: you seldom want to repeat the exact same command, but usually
                     32: one that is close to it.
                     33: To accomplish this you use a special notation called variables to indicate
                     34: where in a command the shell is to substitute the piece of text that
                     35: is to change when the command is repeated.
                     36: 
                     37: In general you can best exploit control statements by using them
                     38: non-interactively, that is, by putting them in command scripts
                     39: so that they decide in your absence which commands to execute,
                     40: when, and how often.
                     41: On the other hand, you can use some of the looping statements
                     42: interactively to great advantage.
                     43: 
                     44: How can a script of commands do different things from one run to
                     45: the next if the text of the commands does not change?
                     46: The answer is:  Only if parts of the commands and decisions
                     47: have been entered by you with the special notation for variables
                     48: and expressions.
                     49: You need a basic working knowledge of variables and expressions
                     50: to understand control statements.
                     51: The next example illustrates the only control structure not requiring
                     52: any special knowledge.
                     53: 
                     54: A Simple Example
                     55: 
                     56: Normally in a shell script or a terminal session, when the shell
                     57: finishes doing one command, it proceeds to do the command
                     58: on the next line, and then the next, and so forth.
                     59: This usually continues until the end of the script file is reached or
                     60: the end of the terminal session (logout).
                     61: Suppose that instead of this normal behavior
                     62: you wanted to execute the same command 10 times.
                     63: In particular, suppose that you wanted 10 lineprinted
                     64: copies of the file "letter".
                     65: The line,
                     66: .IP
                     67: repeat 10 lpr letter
                     68: .LP
                     69: would use the control statement "repeat" to
                     70: cause the command "lpr letter" to be run 10 times.
                     71: Lines such as these are sometimes called control structures
                     72: because they consist of a control part and a command part.
                     73: 
                     74: A More Complicated Example
                     75: 
                     76: Most control structures involve several lines and require variables.
                     77: Here is an example of a 4-line structure which looks up some
                     78: words in the Unix dictionary and then displays on the terminal
                     79: all occurrences of them in a file called "paper".
                     80: .IP
                     81: 'nf
                     82: foreach x (sharp ternimal prestidigitation aint unix)
                     83: look $x
                     84: grep $x paper
                     85: end
                     86: .fi
                     87: .LP
                     88: The "foreach" line tells the shell that it must first scan the succeeding
                     89: lines until it finds one with the keyword "end".
                     90: The two intervening commands will be executed in the order they appear
                     91: as many times as there are words in parentheses.
                     92: Before each cycle of the loop begins,
                     93: the variable "x" is set to the next word in the list.
                     94: In the first cycle, the shell executes the two commands
                     95: using "$x" to signify the word "sharp", that is, it performs the command
                     96: "look sharp" followed by "grep sharp paper".
                     97: Then the shell proceeds with the next word on the list, this time
                     98: performing the two commands using "$x" to signify the
                     99: mispelled word "ternimal".
                    100: This continues for each word on the list until they have all been used,
                    101: at which point the shell resumes its normal operation by
                    102: proceeding to the next command, if any, after the "end" statement.
                    103: 
                    104: A Summary of Control Statements
                    105: 
                    106: There is rarely a situation that requires the use of one
                    107: kind of control statement over another, although some kinds
                    108: are more convenient than others in certain circumstances.
                    109: Here is a summary of the C shell's control statements indicating the
                    110: general form of the first line, special associated words that accompany
                    111: the statement on other lines, whether it is practical to
                    112: use interactively, and the usual purpose.
                    113: 
                    114: .nf
                    115: .ne 8
                    116: Name and First Line  Associated Keywords   Intr?  Usual Purpose
                    117: ---------------------------------------------------------------------------
                    118: if (expression)      then, else, endif      no    conditional branching
                    119: repeat N command                            yes   simple repetition
                    120: while (expression)   end, break, continue   yes   ... until a condition
                    121: foreach x (list)     end, break, continue   yes   ... for each item in list
                    122: goto label           label:                 no    unconditional branching
                    123: switch (expression)  case, endsw, breaksw   no    multi-way value branch
                    124: 
                    125: .fi
                    126: In the examples that follow I will use C shell variables and expressions
                    127: as if you were already somewhat familiar with them.
                    128: Additional explanation sometimes appears in the form of C shell
                    129: comments (annotations) appended to command lines after a # sign.
                    130: Also, I have followed a common convention in programming languages
                    131: in indenting those commands grouped inside control structures.
                    132: 
                    133: The \fBif\fP Statement
                    134: 
                    135: This has several different forms, the first one being
                    136: .IP
                    137: \fBif (\fPexpression\fB)\fP command
                    138: .LP
                    139: where the
                    140: \fIcommand\fP
                    141: is executed only if the
                    142: \fIexpression\fP
                    143: is true.
                    144: Here is a script fragment that informs the user of the number
                    145: of files in the current directory.
                    146: .IP
                    147: 'nf
                    148: set x = (*)                     # variable x gets list of files
                    149: echo -n "There are $#x file"    # $#x is number of files in $x
                    150: if ($#x > 1) echo -n "s"        # if more than 1, make plural
                    151: echo " in this directory."      # end sentence; no -n so add newline
                    152: .fi
                    153: .LP
                    154: Unfortunately, the first form requires the
                    155: \fIcommand\fP
                    156: to be a simple command;
                    157: in other words, no pipelines or multiple commands are allowed,
                    158: even if they are aliased.
                    159: You can avoid this restriction by calling a multi-line
                    160: script in place of \fIcommand\fP, but that takes time.
                    161: It would be more efficient to use the second form of the if statement,
                    162: .IP
                    163: 'nf
                    164: \fBif (\fPexpression\fB) then
                    165:         \fPcommands\fB
                    166:         ...
                    167: else if (\fPexpression\fB) then
                    168:         \fPcommands\fB
                    169:         ...
                    170: \&...
                    171: else
                    172:         \fPcommands\fB
                    173:         ...
                    174: endif\fP
                    175: .fi
                    176: .LP
                    177: The hardest part about this form is to remember
                    178: to type the keyword \fBthen\fP;
                    179: even the most experienced users trip over it fairly often.
                    180: Here is an example of a multi-line \fBif\fP statement
                    181: which checks to see if a file called "readme" exists
                    182: and has read permission; if so it displays it,
                    183: if not it takes other steps.
                    184: .IP
                    185: 'nf
                    186: if (-e readme && -r readme) then     # if it exists and is readable
                    187:         echo "I have a message."     # announce that fact
                    188:         cat readme                   # and display the file
                    189: else if (-e readme) then             # else if it exists only ...
                    190:         echo "I have a message, but cannot read it."
                    191:         exit                         # complain and exit script
                    192: else                                 # else if it doesn't even exist
                    193:         /usr/games/fortune           # do something irrational
                    194: endif                                # this ends the multi-line if
                    195: .fi
                    196: .LP
                    197: 
                    198: The \fBrepeat\fP Statement
                    199: 
                    200: As you may have gathered, the form of this control statement is
                    201: .IP
                    202: \fBrepeat \fIN command\fR
                    203: .LP
                    204: Unfortunately, the \fIcommand\fP part
                    205: suffers the same restrictions here as in the one-line if statement.
                    206: As a result, it is hard to find uses for the repeat statement.
                    207: One example cited occasionally uses it to make 100 copies of one
                    208: file in another file, as in
                    209: .IP
                    210: repeat 100 cat data >> bigdata
                    211: .LP
                    212: A much more efficient way to do this is
                    213: .IP
                    214: cat `jot -b data 100` > bigdata
                    215: .LP
                    216: using command substitution
                    217: (those quote marks should be grave accents).
                    218: Similarly, our earlier example with "lpr" would have
                    219: been better done with
                    220: .IP
                    221: lpr `jot -b letter 10`
                    222: .LP
                    223: 
                    224: The \fBwhile\fP Statement
                    225: 
                    226: The general form of the while statement is
                    227: .IP
                    228: 'nf
                    229: \fBwhile (\fPexpression\fB)
                    230:         commands
                    231:         ...
                    232: end\fP
                    233: .fi
                    234: .LP
                    235: There are no clear cut criteria for determining when to use this
                    236: control statement over another, but in general, use it when
                    237: you want to loop through a sequence of commands until a
                    238: certain condition becomes false.
                    239: On each iteration (cycle through the loop), if \fIexpression\fP
                    240: is true the shell executes the commands up until the
                    241: "end" statement, then begins the next iteration.
                    242: When \fIexpression\fP becomes false, execution continues after
                    243: the "end".
                    244: 
                    245: You can enter the while statement at your terminal as well
                    246: as in a script.
                    247: At the terminal, the shell cannot begin processing until the
                    248: entire body of commands up to the "end" have been entered,
                    249: so each time you press RETURN, it reminds you that it still
                    250: expects you to type in "end" sometime by prompting with a "?".
                    251: For example, to print out the numbers from 1 to 300 on your
                    252: terminal with an interactive while loop,
                    253: .IP
                    254: 'nf
                    255: % set n = 1            # variable n starts out 1
                    256: % while ($n < 301)     # while it's less than 301
                    257: ?       echo $n        # print it out; shell prompt is "?"
                    258: ?       @ n = ($n + 1) # @ is like set, but do arithmetic
                    259: ? end                  # end of loop; loop starts after RETURN
                    260: .fi
                    261: .LP
                    262: A better way to count to 300 would be "jot 300",
                    263: but this example illustrates three points.
                    264: First, most applications in the C shell that require doing
                    265: a command sequence a certain number of times have this general form.
                    266: The condition that the while loop is waiting to become false
                    267: is an arithmetic relation involving a variable that is
                    268: initialized before the loop, changes inside the loop,
                    269: and is tested in the \fIexpression\fP.
                    270: Secondly, any number of commands could have filled up the
                    271: body of the loop, so this provides a way to get around
                    272: the restriction in the repeat statement of repeating
                    273: only a simple command.
                    274: The counting variable, "n" in this case, need not always be
                    275: used except to be incremented.
                    276: Finally, the variable could have been used to count down
                    277: instead of up, to increase by larger increments,
                    278: or to change using any arithmetic operation.
                    279: The \fIexpression\fP could easily be adjusted to test
                    280: for different arithmetic relations.
                    281: 
                    282: As another example, suppose several users need to edit a file called
                    283: "project" from time to time, the contents of which are important
                    284: enough that only one user should be allowed to edit it at a time.
                    285: All the users involved could accomplish this by agreeing among
                    286: themselves only to edit "project" using the script below.
                    287: The while loop causes the shell to
                    288: check every minute whether a file called "lock" exists.
                    289: When it no longer exists, the shell creates the file again,
                    290: letting other users know that someone is currently editing "project",
                    291: and calls up the editor.
                    292: The lock file is removed after editing, and the script is done.
                    293: .IP
                    294: 'nf
                    295: while (-e lock)       # while file "lock" exists ...
                    296:         echo Trying   # tells you that you (still) must wait
                    297:         sleep 60      # do nothing for 60 seconds
                    298: end                   # end of loop; when "lock" gone, proceed
                    299: date > lock           # recreate "lock", no matter what with
                    300: vi project            # call up vi on data being secured
                    301: rm lock               # let others know they can edit "project"
                    302: .fi
                    303: .LP
                    304: The \fBforeach\fP Statement
                    305: 
                    306: The general form of the foreach statement is
                    307: .IP
                    308: 'nf
                    309: \fBforeach \fPvar\fB (\fPword1 word2 \fB...)
                    310:         commands
                    311:         ...
                    312: end\fR
                    313: .fi
                    314: .LP
                    315: As for the while statement there are no clear cut
                    316: criteria for determining when to use the foreach
                    317: statement over another, but in general, use it when
                    318: you want to loop through a sequence of commands to be
                    319: applied to a list of items.
                    320: On each iteration, the variable \fIvar\fP is set to
                    321: the next word in the parenthesized list.
                    322: The shell executes the commands up until the
                    323: "end" statement, then begins the next iteration.
                    324: When there are no unused words left in the list,
                    325: execution continues after the "end".
                    326: The variable \fIvar\fP may be any name you choose,
                    327: and you are not required to use it in the body of the loop.
                    328: Also, the foreach statement is probably used interactively
                    329: more often than any other control structure.
                    330: 
                    331: For example, during a terminal session you could
                    332: mail the files "data1", "data2", etc. up to "data7"
                    333: to a user named "fred" using
                    334: .IP
                    335: 'nf
                    336: % foreach f (data1 data2 data3 data4 data5 data6 data7)
                    337: ?        mail fred < $f
                    338: ? end
                    339: .fi
                    340: .LP
                    341: The list could have been abbreviated with (data[1-7]).
                    342: All the C shell control structures can be nested (used
                    343: inside one another).
                    344: As an example, the following script copies each of the data files
                    345: above into each of the directories "old", "new", and "current".
                    346: .IP
                    347: 'nf
                    348: foreach d (old new current)    # outer loop for directories
                    349:         mkdir $d               # make the target directory
                    350:         foreach f (data[1-7])  # inner loop for files
                    351:                 cp $f $d       # copy (is this efficient?)
                    352:         end                    # end of inner loop
                    353: end                            # end of outer loop
                    354: .fi
                    355: .LP
                    356: This example above is actually rather inefficient
                    357: because the inner loop (3 statements) could have been
                    358: replaced with the single command "cp data[1-7] $d",
                    359: so that the shell would only create one "cp" process
                    360: per directory instead of 7.
                    361: The lesson to learn is that however tempted you may be
                    362: to use the foreach statement, check to see if the command
                    363: involved takes more than one argument.
                    364: 
                    365: The \fBgoto\fP and \fBonintr\fP Statements
                    366: 
                    367: The goto statement consists of the word \fBgoto\fP
                    368: followed be a \fIlabel\fP and causes the shell to jump to a
                    369: line beginning with the string \fIlabel\fP
                    370: followed by a : and to begin executing statements there.
                    371: Strictly speaking all of the C shell's branching and
                    372: looping constructs could be built up using combinations
                    373: of just goto and simple if statements.
                    374: Computer scientists tend to be fanatical in their opposition
                    375: to the goto statement, so try not use it in their presence.
                    376: Here is an example of a script that runs "sed" twice
                    377: on each of the command line arguments.
                    378: When there are no arguments left, the script removes
                    379: a temporary file it created and exits.
                    380: If an argument file is really a directory,
                    381: an error message is printed and the temporary file is not removed.
                    382: .IP
                    383: 'nf
                    384: foreach f ($argv)                     # foreach command argument
                    385:         if (-d $f) goto error         # if a directory, goto error
                    386:         sed -f pass1 $f > /tmp/xyz$$  # sed stores in /tmp/xyz$$
                    387:         sed -f pass2 /tmp/xyz$$ > $f  # then stores back in $f
                    388: end                                   # end of foreach
                    389: goto done:                            # skip the error part
                    390: error:                                # just label, no other effect
                    391: echo Error - $f is a directory.       # print message
                    392: goto end:                             # exit script avoiding "rm"
                    393: done:                                 # just a label
                    394: rm /tmp/xyz$$                         # remove temporary file
                    395: end:                                  # last label, nothing after it
                    396: .LP
                    397: Besides being clumsy, this script would not remove its temporary
                    398: file if the user typed an interrupt to abort the execution prematurely;
                    399: the script would just drop in its tracks.
                    400: This is remedied by the onintr statement, which has the form
                    401: \fBonintr \fIlabel\fR, where \fIlabel\fP is a label to jump
                    402: to whenever the script receives a subsequent interrupt.
                    403: The next example illustrates this, and also converts the goto
                    404: statements into more socially acceptable statements.
                    405: .IP
                    406: 'nf
                    407: onintr done                           # on interrupt, goto done
                    408: foreach f ($argv)                     # foreach command argument
                    409:         if (-d $f) then               # if a directory then ...
                    410:                 echo Error - $f is a directory.
                    411:                 exit                  # exit, but leave temp file
                    412:        endif                         # end of if statement
                    413:         sed -f pass1 $f > /tmp/xyz$$  # sed stores in /tmp/xyz$$
                    414:         sed -f pass2 /tmp/xyz$$ > $f  # then stores back in $f
                    415: end                                   # end of foreach
                    416: done:                                 # label for onintr
                    417: rm /tmp/xyz$$                         # remove temporary file
                    418: .fi
                    419: .LP
                    420: The \fBswitch\fP Statement
                    421: 
                    422: This is like a multi-line if statement which branches only
                    423: on the value of one expression.
                    424: It is usually most useful for visually separating the
                    425: different branches taken in response to different values
                    426: of the same thing.
                    427: Without much further ado, here is a meaningless script fragment that
                    428: processes its arguments through a while loop using a switch statement.
                    429: Just before the each next interaction of the loop, the shift command
                    430: causes the current value of "$argv[1]" to be discarded and replaced
                    431: with "$argv[2]".
                    432: .IP
                    433: 'nf
                    434: while ($#argv > 0)
                    435:         switch ($argv[1])
                    436:         case -m:
                    437:                 set m
                    438:                 breaksw
                    439:         case -l*:
                    440:                 set length = $argv[1]
                    441:                 breaksw
                    442:         case -T:
                    443:                 set sort = (/usr/lib/sort)
                    444:                 set lpr = (/usr/ucb/lpr -Pevans1)
                    445:                 breaksw
                    446:         case -Y:
                    447:                 set sort = (/usr/lib/vsort -W)
                    448:                 set lpr = (/usr/ucb/lpr -Pversatec)
                    449:                 breaksw
                    450:         case -F:
                    451:                 if ($#argv < 2) then
                    452:                         echo -F takes following port name.
                    453:                         exit(1)
                    454:                 endif
                    455:                 set argv = (-1 $2.f -2 $2.p -3 $2.o $argv[3-])
                    456:                breaksw
                    457:         case -1:
                    458:         case -2:
                    459:         case -3:
                    460:                 if ($#argv < 2) then
                    461:                         echo $1 takes following port name.
                    462:                         exit(1)
                    463:                 endif
                    464:                 breaksw
                    465:         case -x:
                    466:                 set xyzzy
                    467:                 breaksw
                    468:         case -*:
                    469:                 set flags = ($flags $argv[1])
                    470:                 breaksw
                    471:         endsw
                    472:         shift argv
                    473: end
                    474: .fi
                    475: .LP
                    476: 
                    477: 
                    478: jak

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.