Annotation of 43BSDTahoe/new/help/src/cshell/flowcontrol, revision 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.