Commit | Line | Data |
---|---|---|
46968dfa C |
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 |