| 1 | .nr H1 2 |
| 2 | .NH |
| 3 | Shell control structures and command scripts |
| 4 | .NH 2 |
| 5 | Introduction |
| 6 | .PP |
| 7 | It is possible to place commands in files and to cause shells to be |
| 8 | invoked to read and execute commands from these files, |
| 9 | which are called |
| 10 | .I "shell scripts." |
| 11 | We here detail those features of the shell useful to the writers of such |
| 12 | scripts. |
| 13 | .NH 2 |
| 14 | Make |
| 15 | .PP |
| 16 | It is important to first note what shell scripts are |
| 17 | .I not |
| 18 | useful for. |
| 19 | There is a program called |
| 20 | .I make |
| 21 | which is very useful for maintaining a group of related files |
| 22 | or performing sets of operations on related files. |
| 23 | For instance a large program consisting of one or more files |
| 24 | can have its dependencies described in a |
| 25 | .I makefile |
| 26 | which contains definitions of the commands used to create these |
| 27 | different files when changes occur. |
| 28 | Definitions of the means for printing listings, cleaning up the directory |
| 29 | in which the files reside, and installing the resultant programs |
| 30 | are easily, and most appropriately placed in this |
| 31 | .I makefile. |
| 32 | This format is superior and preferable to maintaining a group of shell |
| 33 | procedures to maintain these files. |
| 34 | .PP |
| 35 | Similarly when working on a document a |
| 36 | .I makefile |
| 37 | may be created which defines how different versions of the document |
| 38 | are to be created and which options of |
| 39 | .I nroff |
| 40 | or |
| 41 | .I troff |
| 42 | are appropriate. |
| 43 | .NH 2 |
| 44 | Invocation and the argv variable |
| 45 | .PP |
| 46 | A |
| 47 | .I csh |
| 48 | command script may be interpreted by saying |
| 49 | .DS |
| 50 | % csh script ... |
| 51 | .DE |
| 52 | where |
| 53 | .I script |
| 54 | is the name of the file containing a group of |
| 55 | .I csh |
| 56 | commands and |
| 57 | `\&...' is replaced by a sequence of arguments. |
| 58 | The shell places these arguments in the variable |
| 59 | .I argv |
| 60 | and then begins to read commands from the script. |
| 61 | These parameters are then available through the same mechanisms |
| 62 | which are used to reference any other shell variables. |
| 63 | .PP |
| 64 | If you make the file |
| 65 | `script' |
| 66 | executable by doing |
| 67 | .DS |
| 68 | chmod 755 script |
| 69 | .DE |
| 70 | and place a shell comment at the beginning of the shell script |
| 71 | (i.e. begin the file with a `#' character) |
| 72 | then a `/bin/csh' will automatically be invoked to execute `script' when |
| 73 | you type |
| 74 | .DS |
| 75 | script |
| 76 | .DE |
| 77 | If the file does not begin with a `#' then the standard shell |
| 78 | `/bin/sh' will be used to execute it. |
| 79 | This allows you to convert your older shell scripts to use |
| 80 | .I csh |
| 81 | at your convenience. |
| 82 | .NH 2 |
| 83 | Variable substitution |
| 84 | .PP |
| 85 | After each input line is broken into words and history substitutions |
| 86 | are done on it, the input line is parsed into distinct commands. |
| 87 | Before each command is executed a mechanism know as |
| 88 | .I "variable substitution" |
| 89 | is done on these words. |
| 90 | Keyed by the character `$' this substitution replaces the names |
| 91 | of variables by their values. |
| 92 | Thus |
| 93 | .DS |
| 94 | echo $argv |
| 95 | .DE |
| 96 | when placed in a command script would cause the current value of the |
| 97 | variable |
| 98 | .I argv |
| 99 | to be echoed to the output of the shell script. |
| 100 | It is an error for |
| 101 | .I argv |
| 102 | to be unset at this point. |
| 103 | .PP |
| 104 | A number of notations are provided for accessing components and attributes |
| 105 | of variables. |
| 106 | The notation |
| 107 | .DS |
| 108 | $?name |
| 109 | .DE |
| 110 | expands to `1' if name is |
| 111 | .I set |
| 112 | or to `0' |
| 113 | if name is not |
| 114 | .I set. |
| 115 | It is the fundamental mechanism used for checking whether particular |
| 116 | variables have been assigned values. |
| 117 | All other forms of reference to undefined variables cause errors. |
| 118 | .PP |
| 119 | The notation |
| 120 | .DS |
| 121 | $#name |
| 122 | .DE |
| 123 | expands to the number of elements in the variable |
| 124 | .I name. |
| 125 | Thus |
| 126 | .DS |
| 127 | % set argv=(a b c) |
| 128 | % echo $?argv |
| 129 | 1 |
| 130 | % echo $#argv |
| 131 | 3 |
| 132 | % unset argv |
| 133 | % echo $?argv |
| 134 | 0 |
| 135 | % echo $argv |
| 136 | Undefined variable: argv. |
| 137 | % |
| 138 | .DE |
| 139 | .PP |
| 140 | It is also possible to access the components of a variable |
| 141 | which has several values. |
| 142 | Thus |
| 143 | .DS |
| 144 | $argv[1] |
| 145 | .DE |
| 146 | gives the first component of |
| 147 | .I argv |
| 148 | or in the example above `a'. |
| 149 | Similarly |
| 150 | .DS |
| 151 | $argv[$#argv] |
| 152 | .DE |
| 153 | would give `c', |
| 154 | and |
| 155 | .DS |
| 156 | $argv[1\-2] |
| 157 | .DE |
| 158 | would give `a b'. Other notations useful in shell scripts are |
| 159 | .DS |
| 160 | $\fIn\fR |
| 161 | .DE |
| 162 | where |
| 163 | .I n |
| 164 | is an integer as a shorthand for |
| 165 | .DS |
| 166 | $argv[\fIn\fR\|] |
| 167 | .DE |
| 168 | the |
| 169 | .I n\|th |
| 170 | parameter and |
| 171 | .DS |
| 172 | $* |
| 173 | .DE |
| 174 | which is a shorthand for |
| 175 | .DS |
| 176 | $argv |
| 177 | .DE |
| 178 | The form |
| 179 | .DS |
| 180 | $$ |
| 181 | .DE |
| 182 | expands to the process number of the current shell. |
| 183 | Since this process number is unique in the system it can |
| 184 | be used in generation of unique temporary file names. |
| 185 | The form |
| 186 | .DS |
| 187 | $< |
| 188 | .DE |
| 189 | is quite special and is replaced by the next line of input read from |
| 190 | the shell's standard input (not the script it is reading). This is |
| 191 | useful for writing shell scripts that are interactive, reading |
| 192 | commands from the terminal, or even writing a shell script that |
| 193 | acts as a filter, reading lines from its input file. Thus the sequence |
| 194 | .DS |
| 195 | echo 'yes or no?\ec' |
| 196 | set a=($<) |
| 197 | .DE |
| 198 | would write out the prompt `yes or no?' without a newline and then |
| 199 | read the answer into the variable `a'. In this case `$#a' would be |
| 200 | `0' if either a blank line or end-of-file (\(uaD) was typed. |
| 201 | .PP |
| 202 | One minor difference between `$\fIn\fR\|' and `$argv[\fIn\fR\|]' |
| 203 | should be noted here. |
| 204 | The form |
| 205 | `$argv[\fIn\fR\|]' |
| 206 | will yield an error if |
| 207 | .I n |
| 208 | is not in the range |
| 209 | `1\-$#argv' |
| 210 | while `$n' |
| 211 | will never yield an out of range subscript error. |
| 212 | This is for compatibility with the way older shells handled parameters. |
| 213 | .PP |
| 214 | Another important point is that it is never an error to give a subrange |
| 215 | of the form `n\-'; if there are less than |
| 216 | .I n |
| 217 | components of the given variable then no words are substituted. |
| 218 | A range of the form `m\-n' likewise returns an empty vector without giving |
| 219 | an error when \fIm\fR exceeds the number of elements of the given variable, |
| 220 | provided the subscript \fIn\fR is in range. |
| 221 | .NH 2 |
| 222 | Expressions |
| 223 | .PP |
| 224 | In order for interesting shell scripts to be constructed it |
| 225 | must be possible to evaluate expressions in the shell based on the |
| 226 | values of variables. |
| 227 | In fact, all the arithmetic operations of the language C are available |
| 228 | in the shell |
| 229 | with the same precedence that they have in C. |
| 230 | In particular, the operations `==' and `!=' compare strings |
| 231 | and the operators `&&' and `|\|\||' implement the boolean and/or operations. |
| 232 | The special operators `=~' and `!~' are similar to `==' and `!=' except |
| 233 | that the string on the right side can have pattern matching characters |
| 234 | (like *, ? or []) and the test is whether the string on the left matches |
| 235 | the pattern on the right. |
| 236 | .PP |
| 237 | The shell also allows file enquiries of the form |
| 238 | .DS |
| 239 | \-? filename |
| 240 | .DE |
| 241 | where `?' is replace by a number of single characters. |
| 242 | For instance the expression primitive |
| 243 | .DS |
| 244 | \-e filename |
| 245 | .DE |
| 246 | tell whether the file |
| 247 | `filename' |
| 248 | exists. |
| 249 | Other primitives test for read, write and execute access to the file, |
| 250 | whether it is a directory, or has non-zero length. |
| 251 | .PP |
| 252 | It is possible to test whether a command terminates normally, |
| 253 | by a primitive of the |
| 254 | form `{ command }' which returns true, i.e. `1' if the command |
| 255 | succeeds exiting normally with exit status 0, or `0' if the command |
| 256 | terminates abnormally or with exit status non-zero. |
| 257 | If more detailed information about the execution status of a command |
| 258 | is required, it can be executed and the variable `$status' examined |
| 259 | in the next command. |
| 260 | Since `$status' is set by every command, it is very transient. |
| 261 | It can be saved if it is inconvenient to use it only in the single |
| 262 | immediately following command. |
| 263 | .PP |
| 264 | For a full list of expression components available see the manual |
| 265 | section for the shell. |
| 266 | .NH 2 |
| 267 | Sample shell script |
| 268 | .PP |
| 269 | A sample shell script which makes use of the expression mechanism |
| 270 | of the shell and some of its control structure follows: |
| 271 | .DS |
| 272 | % cat copyc |
| 273 | # |
| 274 | # Copyc copies those C programs in the specified list |
| 275 | # to the directory ~/backup if they differ from the files |
| 276 | # already in ~/backup |
| 277 | # |
| 278 | set noglob |
| 279 | foreach i ($argv) |
| 280 | |
| 281 | if ($i !~ *.c) continue # not a .c file so do nothing |
| 282 | |
| 283 | if (! \-r ~/backup/$i:t) then |
| 284 | echo $i:t not in backup... not cp\e\'ed |
| 285 | continue |
| 286 | endif |
| 287 | |
| 288 | cmp \-s $i ~/backup/$i:t # to set $status |
| 289 | |
| 290 | if ($status != 0) then |
| 291 | echo new backup of $i |
| 292 | cp $i ~/backup/$i:t |
| 293 | endif |
| 294 | end |
| 295 | .DE |
| 296 | .PP |
| 297 | This script makes use of the |
| 298 | .I foreach |
| 299 | command, which causes the shell to execute the commands between the |
| 300 | .I foreach |
| 301 | and the matching |
| 302 | .I end |
| 303 | for each of the values given between `(' and `)' with the named |
| 304 | variable, in this case `i' set to successive values in the list. |
| 305 | Within this loop we may use the command |
| 306 | .I break |
| 307 | to stop executing the loop |
| 308 | and |
| 309 | .I continue |
| 310 | to prematurely terminate one iteration |
| 311 | and begin the next. |
| 312 | After the |
| 313 | .I foreach |
| 314 | loop the iteration variable |
| 315 | (\fIi\fR in this case) |
| 316 | has the value at the last iteration. |
| 317 | .PP |
| 318 | We set the variable |
| 319 | .I noglob |
| 320 | here to prevent filename expansion of the members of |
| 321 | .I argv. |
| 322 | This is a good idea, in general, if the arguments to a shell script |
| 323 | are filenames which have already been expanded or if the arguments |
| 324 | may contain filename expansion metacharacters. |
| 325 | It is also possible to quote each use of a `$' variable expansion, |
| 326 | but this is harder and less reliable. |
| 327 | .PP |
| 328 | The other control construct used here is a statement of the form |
| 329 | .DS |
| 330 | \fBif\fR ( expression ) \fBthen\fR |
| 331 | command |
| 332 | ... |
| 333 | \fBendif\fR |
| 334 | .DE |
| 335 | The placement of the keywords here is |
| 336 | .B not |
| 337 | flexible due to the current implementation of the shell.\(dg |
| 338 | .FS |
| 339 | \(dgThe following two formats are not currently acceptable to the shell: |
| 340 | .sp |
| 341 | .in +5 |
| 342 | .nf |
| 343 | \fBif\fR ( expression ) # \fBWon't work!\fR |
| 344 | \fBthen\fR |
| 345 | command |
| 346 | ... |
| 347 | \fBendif\fR |
| 348 | .fi |
| 349 | .in -5 |
| 350 | .sp |
| 351 | and |
| 352 | .sp |
| 353 | .in +5 |
| 354 | .nf |
| 355 | \fBif\fR ( expression ) \fBthen\fR command \fBendif\fR # \fBWon't work\fR |
| 356 | .in -5 |
| 357 | .fi |
| 358 | .FE |
| 359 | .PP |
| 360 | The shell does have another form of the if statement of the form |
| 361 | .DS |
| 362 | \fBif\fR ( expression ) \fBcommand\fR |
| 363 | .DE |
| 364 | which can be written |
| 365 | .DS |
| 366 | \fBif\fR ( expression ) \e |
| 367 | command |
| 368 | .DE |
| 369 | Here we have escaped the newline for the sake of appearance. |
| 370 | The command must not involve `\||\|', `&' or `;' |
| 371 | and must not be another control command. |
| 372 | The second form requires the final `\e' to |
| 373 | .B immediately |
| 374 | precede the end-of-line. |
| 375 | .PP |
| 376 | The more general |
| 377 | .I if |
| 378 | statements above also admit a sequence of |
| 379 | .I else\-if |
| 380 | pairs followed by a single |
| 381 | .I else |
| 382 | and an |
| 383 | .I endif, |
| 384 | e.g.: |
| 385 | .DS |
| 386 | \fBif\fR ( expression ) \fBthen\fR |
| 387 | commands |
| 388 | \fBelse\fR \fBif\fR (expression ) \fBthen\fR |
| 389 | commands |
| 390 | \&... |
| 391 | |
| 392 | \fBelse\fR |
| 393 | commands |
| 394 | \fBendif\fR |
| 395 | .DE |
| 396 | .PP |
| 397 | Another important mechanism used in shell scripts is the `:' modifier. |
| 398 | We can use the modifier `:r' here to extract a root of a filename or |
| 399 | `:e' to extract the |
| 400 | .I extension. |
| 401 | Thus if the variable |
| 402 | .I i |
| 403 | has the value |
| 404 | `/mnt/foo.bar' |
| 405 | then |
| 406 | .sp |
| 407 | .in +5 |
| 408 | .nf |
| 409 | % echo $i $i:r $i:e |
| 410 | /mnt/foo.bar /mnt/foo bar |
| 411 | % |
| 412 | .sp |
| 413 | .in -5 |
| 414 | .fi |
| 415 | shows how the `:r' modifier strips off the trailing `.bar' and the |
| 416 | the `:e' modifier leaves only the `bar'. |
| 417 | Other modifiers will take off the last component of a pathname leaving |
| 418 | the head `:h' or all but the last component of a pathname leaving the |
| 419 | tail `:t'. |
| 420 | These modifiers are fully described in the |
| 421 | .I csh |
| 422 | manual pages in the programmers manual. |
| 423 | It is also possible to use the |
| 424 | .I "command substitution" |
| 425 | mechanism described in the next major section to perform modifications |
| 426 | on strings to then reenter the shells environment. |
| 427 | Since each usage of this mechanism involves the creation of a new process, |
| 428 | it is much more expensive to use than the `:' modification mechanism.# |
| 429 | .FS |
| 430 | #It is also important to note that |
| 431 | the current implementation of the shell limits the number of `:' modifiers |
| 432 | on a `$' substitution to 1. |
| 433 | Thus |
| 434 | .sp |
| 435 | .nf |
| 436 | .in +5 |
| 437 | % echo $i $i:h:t |
| 438 | /a/b/c /a/b:t |
| 439 | % |
| 440 | .in -5 |
| 441 | .fi |
| 442 | .sp |
| 443 | does not do what one would expect. |
| 444 | .FE |
| 445 | Finally, we note that the character `#' lexically introduces a shell |
| 446 | comment in shell scripts (but not from the terminal). |
| 447 | All subsequent characters on the input line after a `#' are discarded |
| 448 | by the shell. |
| 449 | This character can be quoted using `\'' or `\e' to place it in |
| 450 | an argument word. |
| 451 | .NH 2 |
| 452 | Other control structures |
| 453 | .PP |
| 454 | The shell also has control structures |
| 455 | .I while |
| 456 | and |
| 457 | .I switch |
| 458 | similar to those of C. |
| 459 | These take the forms |
| 460 | .DS |
| 461 | \fBwhile\fR ( expression ) |
| 462 | commands |
| 463 | \fBend\fR |
| 464 | .DE |
| 465 | and |
| 466 | .DS |
| 467 | \fBswitch\fR ( word ) |
| 468 | |
| 469 | \fBcase\fR str1: |
| 470 | commands |
| 471 | \fBbreaksw\fR |
| 472 | |
| 473 | \& ... |
| 474 | |
| 475 | \fBcase\fR strn: |
| 476 | commands |
| 477 | \fBbreaksw\fR |
| 478 | |
| 479 | \fBdefault:\fR |
| 480 | commands |
| 481 | \fBbreaksw\fR |
| 482 | |
| 483 | \fBendsw\fR |
| 484 | .DE |
| 485 | For details see the manual section for |
| 486 | .I csh. |
| 487 | C programmers should note that we use |
| 488 | .I breaksw |
| 489 | to exit from a |
| 490 | .I switch |
| 491 | while |
| 492 | .I break |
| 493 | exits a |
| 494 | .I while |
| 495 | or |
| 496 | .I foreach |
| 497 | loop. |
| 498 | A common mistake to make in |
| 499 | .I csh |
| 500 | scripts is to use |
| 501 | .I break |
| 502 | rather than |
| 503 | .I breaksw |
| 504 | in switches. |
| 505 | .PP |
| 506 | Finally, |
| 507 | .I csh |
| 508 | allows a |
| 509 | .I goto |
| 510 | statement, with labels looking like they do in C, i.e.: |
| 511 | .DS |
| 512 | loop: |
| 513 | commands |
| 514 | \fBgoto\fR loop |
| 515 | .DE |
| 516 | .NH 2 |
| 517 | Supplying input to commands |
| 518 | .PP |
| 519 | Commands run from shell scripts receive by default the standard |
| 520 | input of the shell which is running the script. |
| 521 | This is different from previous shells running |
| 522 | under \s-2UNIX\s0. It allows shell scripts to fully participate |
| 523 | in pipelines, but mandates extra notation for commands which are to take |
| 524 | inline data. |
| 525 | .PP |
| 526 | Thus we need a metanotation for supplying inline data to commands in |
| 527 | shell scripts. |
| 528 | As an example, consider this script which runs the editor to |
| 529 | delete leading blanks from the lines in each argument file |
| 530 | .DS |
| 531 | % cat deblank |
| 532 | # deblank \-\- remove leading blanks |
| 533 | foreach i ($argv) |
| 534 | ed \- $i << \'EOF\' |
| 535 | 1,$s/\(ua[ ]*// |
| 536 | w |
| 537 | q |
| 538 | \&\'EOF\' |
| 539 | end |
| 540 | % |
| 541 | .DE |
| 542 | The notation `<< \'EOF\'' |
| 543 | means that the standard input for the |
| 544 | .I ed |
| 545 | command is to come from the text in the shell script file |
| 546 | up to the next line consisting of exactly `\'EOF\''. |
| 547 | The fact that the `EOF' is enclosed in `\'' characters, i.e. quoted, |
| 548 | causes the shell to not perform variable substitution on the |
| 549 | intervening lines. |
| 550 | In general, if any part of the word following the `<<' which the |
| 551 | shell uses to terminate the text to be given to the command is quoted |
| 552 | then these substitutions will not be performed. |
| 553 | In this case since we used the form `1,$' in our editor script |
| 554 | we needed to insure that this `$' was not variable substituted. |
| 555 | We could also have insured this by preceding the `$' here with a `\e', |
| 556 | i.e.: |
| 557 | .DS |
| 558 | 1,\e$s/\(ua[ ]*// |
| 559 | .DE |
| 560 | but quoting the `EOF' terminator is a more reliable way of achieving the |
| 561 | same thing. |
| 562 | .NH 2 |
| 563 | Catching interrupts |
| 564 | .PP |
| 565 | If our shell script creates temporary files, we may wish to catch |
| 566 | interruptions of the shell script so that we can clean up |
| 567 | these files. |
| 568 | We can then do |
| 569 | .DS |
| 570 | onintr label |
| 571 | .DE |
| 572 | where |
| 573 | .I label |
| 574 | is a label in our program. |
| 575 | If an interrupt is received the shell will do a |
| 576 | `goto label' |
| 577 | and we can remove the temporary files and then do an |
| 578 | .I exit |
| 579 | command (which is built in to the shell) |
| 580 | to exit from the shell script. |
| 581 | If we wish to exit with a non-zero status we can do |
| 582 | .DS |
| 583 | exit(1) |
| 584 | .DE |
| 585 | e.g. to exit with status `1'. |
| 586 | .NH 2 |
| 587 | What else? |
| 588 | .PP |
| 589 | There are other features of the shell useful to writers of shell |
| 590 | procedures. |
| 591 | The |
| 592 | .I verbose |
| 593 | and |
| 594 | .I echo |
| 595 | options and the related |
| 596 | .I \-v |
| 597 | and |
| 598 | .I \-x |
| 599 | command line options can be used to help trace the actions of the shell. |
| 600 | The |
| 601 | .I \-n |
| 602 | option causes the shell only to read commands and not to execute |
| 603 | them and may sometimes be of use. |
| 604 | .PP |
| 605 | One other thing to note is that |
| 606 | .I csh |
| 607 | will not execute shell scripts which do not begin with the |
| 608 | character `#', that is shell scripts that do not begin with a comment. |
| 609 | Similarly, the `/bin/sh' on your system may well defer to `csh' |
| 610 | to interpret shell scripts which begin with `#'. |
| 611 | This allows shell scripts for both shells to live in harmony. |
| 612 | .PP |
| 613 | There is also another quotation mechanism using `"' which allows |
| 614 | only some of the expansion mechanisms we have so far discussed to occur |
| 615 | on the quoted string and serves to make this string into a single word |
| 616 | as `\'' does. |
| 617 | .bp |