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