|
|
1.1 root 1: .\" @(#)t2 6.2 (Berkeley) 9/12/88
2: .\"
3: .SH
4: 2.0\ Shell\ procedures
5: .LP
6: The shell may be used to read and execute commands
7: contained in a file.
8: For example,
9: .DS
10: sh file [ args \*(ZZ ]
11: .DE
12: calls the shell to read commands from \fIfile.\fP
13: Such a file is called a \fIcommand procedure\fP
14: or \fIshell procedure.\fP
15: Arguments may be supplied with the call
16: and are referred to in \fIfile\fP
17: using the positional parameters
18: \fB$1, $2, \*(ZZ\|.\fR
19: For example, if the file \fIwg\fP contains
20: .DS
21: who \*(VT grep $1
22: .DE
23: then
24: .DS
25: sh wg fred
26: .DE
27: is equivalent to
28: .DS
29: who \*(VT grep fred
30: .DE
31: .LP
32: UNIX files have three independent attributes,
33: \fIread,\fP \fIwrite\fP and \fIexecute.\fP
34: The UNIX command \fIchmod\fP (1) may be used
35: to make a file executable.
36: For example,
37: .DS
38: chmod +x wg
39: .DE
40: will ensure that the file \fIwg\fP has execute status.
41: Following this, the command
42: .DS
43: wg fred
44: .DE
45: is equivalent to
46: .DS
47: sh wg fred
48: .DE
49: This allows shell procedures and programs
50: to be used interchangeably.
51: In either case a new process is created to
52: run the command.
53: .LP
54: As well as providing names for the positional
55: parameters,
56: the number of positional parameters in the call
57: is available as \fB$#\|.\fP
58: The name of the file being executed
59: is available as \fB$0\|.\fP
60: .LP
61: A special shell parameter \fB$\*(ST\fP
62: is used to substitute for all positional parameters
63: except \fB$0\|.\fP
64: A typical use of this is to provide
65: some default arguments,
66: as in,
67: .DS
68: nroff \(miT450 \(mims $\*(ST
69: .DE
70: which simply prepends some arguments
71: to those already given.
72: .SH
73: 2.1\ Control\ flow\ -\ for
74: .LP
75: A frequent use of shell procedures is to loop
76: through the arguments (\fB$1, $2, \*(ZZ\fR)
77: executing commands once for each argument.
78: An example of such a procedure is
79: \fItel\fP that searches the file
80: \fB/usr/lib/telnos\fR
81: that contains lines of the form
82: .DS
83: \*(ZZ
84: fred mh0123
85: bert mh0789
86: \*(ZZ
87: .DE
88: The text of \fItel\fP is
89: .DS
90: for i
91: do grep $i /usr/lib/telnos; done
92: .DE
93: The command
94: .DS
95: tel fred
96: .DE
97: prints those lines in \fB/usr/lib/telnos\fR
98: that contain the string \fIfred\|.\fP
99: .DS
100: tel fred bert
101: .DE
102: prints those lines containing \fIfred\fP
103: followed by those for \fIbert.\fP
104: .LP
105: The \fBfor\fP loop notation is recognized by the shell
106: and has the general form
107: .DS
108: \fBfor\fR \fIname\fR \fBin\fR \fIw1 w2 \*(ZZ\fR
109: \fBdo\fR \fIcommand-list\fR
110: \fBdone\fR
111: .DE
112: A \fIcommand-list\fP is a sequence of one or more
113: simple commands separated or terminated by a newline or semicolon.
114: Furthermore, reserved words
115: like \fBdo\fP and \fBdone\fP are only
116: recognized following a newline or
117: semicolon.
118: \fIname\fP is a shell variable that is set
119: to the words \fIw1 w2 \*(ZZ\fR in turn each time the \fIcommand-list\fP
120: following \fBdo\fP
121: is executed.
122: If \fBin\fR \fIw1 w2 \*(ZZ\fR
123: is omitted then the loop
124: is executed once for each positional parameter;
125: that is, \fBin\fR \fI$\*(ST\fR is assumed.
126: .LP
127: Another example of the use of the \fBfor\fP
128: loop is the \fIcreate\fP command
129: whose text is
130: .DS
131: for i do >$i; done
132: .DE
133: The command
134: .DS
135: create alpha beta
136: .DE
137: ensures that two empty files
138: \fIalpha\fP and \fIbeta\fP exist
139: and are empty.
140: The notation \fI>file\fP may be used on its
141: own to create or clear the contents of a file.
142: Notice also that a semicolon (or newline) is required before \fBdone.\fP
143: .SH
144: 2.2\ Control\ flow\ -\ case
145: .LP
146: A multiple way branch is provided for by the
147: \fBcase\fP notation.
148: For example,
149: .DS
150: case $# in
151: \*(Ca1) cat \*(AP$1 ;;
152: \*(Ca2) cat \*(AP$2 <$1 ;;
153: \*(Ca\*(ST) echo \\'usage: append [ from ] to\\' ;;
154: esac
155: .DE
156: is an \fIappend\fP command.
157: When called
158: with one argument as
159: .DS
160: append file
161: .DE
162: \fB$#\fP is the string \fI1\fP and
163: the standard input is copied onto the
164: end of \fIfile\fP
165: using the \fIcat\fP command.
166: .DS
167: append file1 file2
168: .DE
169: appends the contents of \fIfile1\fP
170: onto \fIfile2.\fP
171: If the number of arguments supplied to
172: \fIappend\fP is other than 1 or 2
173: then a message is printed indicating
174: proper usage.
175: .LP
176: The general form of the \fBcase\fP command
177: is
178: .DS
179: \fBcase \fIword \fBin
180: \*(Ca\fIpattern\|\fB)\ \fIcommand-list\fB\|;;
181: \*(Ca\*(ZZ
182: \fBesac\fR
183: .DE
184: The shell attempts to match
185: \fIword\fR with each \fIpattern,\fR
186: in the order in which the patterns
187: appear.
188: If a match is found the
189: associated \fIcommand-list\fP is
190: executed and execution
191: of the \fBcase\fP is complete.
192: Since \*(ST is the pattern that matches any
193: string it can be used for the default case.
194: .LP
195: A word of caution:
196: no check is made to ensure that only
197: one pattern matches
198: the case argument.
199: The first match found defines the set of commands
200: to be executed.
201: In the example below the commands following
202: the second \*(ST will never be executed.
203: .DS
204: case $# in
205: \*(Ca\*(ST) \*(ZZ ;;
206: \*(Ca\*(ST) \*(ZZ ;;
207: esac
208: .DE
209: .LP
210: Another example of the use of the \fBcase\fP
211: construction is to distinguish
212: between different forms
213: of an argument.
214: The following example is a fragment of a \fIcc\fP command.
215: .DS
216: for i
217: do case $i in
218: \*(DC\(mi[ocs]) \*(ZZ ;;
219: \*(DC\(mi\*(ST) echo \\"unknown flag $i\\" ;;
220: \*(DC\*(ST.c) /lib/c0 $i \*(ZZ ;;
221: \*(DC\*(ST) echo \\"unexpected argument $i\\" ;;
222: \*(DOesac
223: done
224: .DE
225: .LP
226: To allow the same commands to be associated
227: with more than one pattern
228: the \fBcase\fP command provides
229: for alternative patterns
230: separated by a \*(VT\|.
231: For example,
232: .DS
233: case $i in
234: \*(Ca\(mix\*(VT\(miy) \*(ZZ
235: esac
236: .DE
237: is equivalent to
238: .DS
239: case $i in
240: \*(Ca\(mi[xy]) \*(ZZ
241: esac
242: .DE
243: .LP
244: The usual quoting conventions apply
245: so that
246: .DS
247: case $i in
248: \*(Ca\\\\?) \*(ZZ
249: .DE
250: will match the character \fB?\|.\fP
251: .SH
252: 2.3\ Here\ documents
253: .LP
254: The shell procedure \fItel\fP
255: in section 2.1 uses the file \fB/usr/lib/telnos\fR
256: to supply the data
257: for \fIgrep.\fP
258: An alternative is to include this
259: data
260: within the shell procedure as a \fIhere\fP document, as in,
261: .DS
262: for i
263: do grep $i \*(HE!
264: \*(DO\*(ZZ
265: \*(DOfred mh0123
266: \*(DObert mh0789
267: \*(DO\*(ZZ
268: !
269: done
270: .DE
271: In this example
272: the shell takes the lines between \fB\*(HE!\fR and \fB!\fR
273: as the standard input for \fIgrep.\fP
274: The string \fB!\fR is arbitrary, the document
275: being terminated by a line that consists
276: of the string following \*(HE\|.
277: .LP
278: Parameters are substituted in the document
279: before it is made available to \fIgrep\fP
280: as illustrated by the following procedure
281: called \fIedg\|.\fP
282: .DS
283: ed $3 \*(HE%
284: g/$1/s//$2/g
285: w
286: %
287: .DE
288: The call
289: .DS
290: edg string1 string2 file
291: .DE
292: is then equivalent to the command
293: .DS
294: ed file \*(HE%
295: g/string1/s//string2/g
296: w
297: %
298: .DE
299: and changes all occurrences of \fIstring1\fP
300: in \fIfile\fP to \fIstring2\|.\fP
301: Substitution can be prevented using \\
302: to quote the special character \fB$\fP
303: as in
304: .DS
305: ed $3 \*(HE+
306: 1,\\\\$s/$1/$2/g
307: w
308: +
309: .DE
310: (This version of \fIedg\fP is equivalent to
311: the first except that \fIed\fP will print
312: a \fB?\fR if there are no occurrences of
313: the string \fB$1\|.\fP)
314: Substitution within a \fIhere\fP document
315: may be prevented entirely by quoting
316: the terminating string,
317: for example,
318: .DS
319: grep $i \*(HE\\\\#
320: \*(ZZ
321: #
322: .DE
323: The document is presented
324: without modification to \fIgrep.\fP
325: If parameter substitution is not required
326: in a \fIhere\fP document this latter form
327: is more efficient.
328: .SH
329: 2.4\ Shell\ variables
330: .LP
331: The shell
332: provides string-valued variables.
333: Variable names begin with a letter
334: and consist of letters, digits and
335: underscores.
336: Variables may be given values by writing, for example,
337: .DS
338: user=fred\ box=m000\ acct=mh0000
339: .DE
340: which assigns values to the variables
341: \fBuser, box\fP and \fBacct.\fP
342: A variable may be set to the null string
343: by saying, for example,
344: .DS
345: null=
346: .DE
347: The value of a variable is substituted
348: by preceding its name with \fB$\|;\fP
349: for example,
350: .DS
351: echo $user
352: .DE
353: will echo \fIfred.\fP
354: .LP
355: Variables may be used interactively
356: to provide abbreviations for frequently
357: used strings.
358: For example,
359: .DS
360: b=/usr/fred/bin
361: mv pgm $b
362: .DE
363: will move the file \fIpgm\fP
364: from the current directory to the directory \fB/usr/fred/bin\|.\fR
365: A more general notation is available for parameter
366: (or variable)
367: substitution, as in,
368: .DS
369: echo ${user}
370: .DE
371: which is equivalent to
372: .DS
373: echo $user
374: .DE
375: and is used when the parameter name is
376: followed by a letter or digit.
377: For example,
378: .DS
379: tmp=/tmp/ps
380: ps a >${tmp}a
381: .DE
382: will direct the output of \fIps\fR
383: to the file \fB/tmp/psa,\fR
384: whereas,
385: .DS
386: ps a >$tmpa
387: .DE
388: would cause the value of the variable \fBtmpa\fP
389: to be substituted.
390: .LP
391: Except for \fB$?\fP the following
392: are set initially by the shell.
393: \fB$?\fP is set after executing each command.
394: .RS
395: .IP \fB$?\fP 8
396: The exit status (return code)
397: of the last command executed
398: as a decimal string.
399: Most commands return a zero exit status
400: if they complete successfully,
401: otherwise a non-zero exit status is returned.
402: Testing the value of return codes is dealt with
403: later under \fBif\fP and \fBwhile\fP commands.
404: .IP \fB$#\fP 8
405: The number of positional parameters
406: (in decimal).
407: Used, for example, in the \fIappend\fP command
408: to check the number of parameters.
409: .IP \fB$$\fP 8
410: The process number of this shell (in decimal).
411: Since process numbers are unique among
412: all existing processes, this string is
413: frequently used to generate
414: unique
415: temporary file names.
416: For example,
417: .DS
418: ps a >/tmp/ps$$
419: \*(ZZ
420: rm /tmp/ps$$
421: .DE
422: .IP \fB$\|!\fP 8
423: The process number of the last process
424: run in the background (in decimal).
425: .IP \fB$\(mi\fP 8
426: The current shell flags, such as
427: \fB\(mix\fR and \fB\(miv\|.\fR
428: .RE
429: .LP
430: Some variables have a special meaning to the
431: shell and should be avoided for general
432: use.
433: .RS
434: .IP \fB$\s-1MAIL\s0\fP 8
435: When used interactively
436: the shell looks at the file
437: specified by this variable
438: before it issues a prompt.
439: If the specified file has been modified
440: since it
441: was last looked at the shell
442: prints the message
443: \fIyou have mail\fP before prompting
444: for the next command.
445: This variable is typically set
446: in the file \fB.profile,\fP
447: in the user's login directory.
448: For example,
449: .DS
450: \s-1MAIL\s0=/usr/spool/mail/fred
451: .DE
452: .IP \fB$\s-1HOME\s0\fP 8
453: The default argument
454: for the \fIcd\fP command.
455: The current directory is used to resolve
456: file name references that do not begin with
457: a \fB/\|,\fR
458: and is changed using the \fIcd\fP command.
459: For example,
460: .DS
461: cd /usr/fred/bin
462: .DE
463: makes the current directory \fB/usr/fred/bin\|.\fR
464: .DS
465: cat wn
466: .DE
467: will print on the terminal the file \fIwn\fP
468: in this directory.
469: The command
470: \fIcd\fP with no argument
471: is equivalent to
472: .DS
473: cd $\s-1HOME\s0
474: .DE
475: This variable is also typically set in the
476: the user's login profile.
477: .IP \fB$\s-1PATH\s0\fP 8
478: A list of directories that contain commands (the \fIsearch path\fR\|).
479: Each time a command is executed by the shell
480: a list of directories is searched
481: for an executable file.
482: .ne 5
483: If \fB$\s-1PATH\s0\fP is not set
484: then the current directory,
485: \fB/bin\fP, and \fB/usr/bin\fP are searched by default.
486: .ne 5
487: Otherwise \fB$\s-1PATH\s0\fP consists of directory
488: names separated by \fB:\|.\fP
489: For example,
490: .DS
491: \s-1PATH\s0=\fB:\fP/usr/fred/bin\fB:\fP/bin\fB:\fP/usr/bin
492: .DE
493: specifies that the current directory
494: (the null string before the first \fB:\fP\|),
495: \fB/usr/fred/bin, /bin \fRand\fP /usr/bin\fR
496: are to be searched in that order.
497: In this way individual users
498: can have their own `private' commands
499: that are accessible independently
500: of the current directory.
501: If the command name contains a \fB/\fR then this directory search
502: is not used; a single attempt
503: is made to execute the command.
504: .IP \fB$\s-1PS1\s0\fP 8
505: The primary shell prompt string, by default, `\fB$\ \fR'.
506: .IP \fB$\s-1PS2\s0\fP 8
507: The shell prompt when further input is needed,
508: by default, `\fB>\ \fR'.
509: .IP \fB$\s-1IFS\s0\fP 8
510: The set of characters used by \fIblank
511: interpretation\fR (see section 3.4).
512: .RE
513: .SH
514: 2.5\ The\ test\ command
515: .LP
516: The \fItest\fP command, although not part of the shell,
517: is intended for use by shell programs.
518: For example,
519: .DS
520: test \(mif file
521: .DE
522: returns zero exit status if \fIfile\fP
523: exists and non-zero exit status otherwise.
524: In general \fItest\fP evaluates a predicate
525: and returns the result as its exit status.
526: Some of the more frequently used \fItest\fP
527: arguments are given here, see \fItest\fP (1)
528: for a complete specification.
529: .DS
530: test s true if the argument \fIs\fP is not the null string
531: test \(mif file true if \fIfile\fP exists
532: test \(mir file true if \fIfile\fP is readable
533: test \(miw file true if \fIfile\fP is writable
534: test \(mid file true if \fIfile\fP is a directory
535: .DE
536: .SH
537: 2.6\ Control\ flow\ -\ while
538: .LP
539: The actions of
540: the \fBfor\fP loop and the \fBcase\fP
541: branch are determined by data available to the shell.
542: A \fBwhile\fP or \fBuntil\fP loop
543: and an \fBif then else\fP branch
544: are also provided whose
545: actions are determined by the exit status
546: returned by commands.
547: A \fBwhile\fP loop has the general form
548: .DS
549: \fBwhile\fP \fIcommand-list\*1\fP
550: \fBdo\fP \fIcommand-list\*2\fP
551: \fBdone\fP
552: .DE
553: .LP
554: The value tested by the \fBwhile\fP command
555: is the exit status of the last simple command
556: following \fBwhile.\fP
557: Each time round the loop
558: \fIcommand-list\*1\fP is executed;
559: if a zero exit status is returned then
560: \fIcommand-list\*2\fP
561: is executed;
562: otherwise, the loop terminates.
563: For example,
564: .DS
565: while test $1
566: do \*(ZZ
567: \*(DOshift
568: done
569: .DE
570: is equivalent to
571: .DS
572: for i
573: do \*(ZZ
574: done
575: .DE
576: \fIshift\fP is a shell command that
577: renames the positional parameters
578: \fB$2, $3, \*(ZZ\fR as \fB$1, $2, \*(ZZ\fR
579: and loses \fB$1\|.\fP
580: .LP
581: Another kind of use for the \fBwhile/until\fP
582: loop is to wait until some
583: external event occurs and then run
584: some commands.
585: In an \fBuntil\fP loop
586: the termination condition is reversed.
587: For example,
588: .DS
589: until test \(mif file
590: do sleep 300; done
591: \fIcommands\fP
592: .DE
593: will loop until \fIfile\fP exists.
594: Each time round the loop it waits for
595: 5 minutes before trying again.
596: (Presumably another process
597: will eventually create the file.)
598: .SH
599: 2.7\ Control\ flow\ -\ if
600: .LP
601: Also available is a
602: general conditional branch
603: of the form,
604: .DS
605: \fBif\fP \fIcommand-list
606: \fBthen \fIcommand-list
607: \fBelse \fIcommand-list
608: \fBfi\fR
609: .DE
610: that tests the value returned by the last simple command
611: following \fBif.\fP
612: .LP
613: The \fBif\fP command may be used
614: in conjunction with the \fItest\fP command
615: to test for the existence of a file as in
616: .DS
617: if test \(mif file
618: then \fIprocess file\fP
619: else \fIdo something else\fP
620: fi
621: .DE
622: .LP
623: An example of the use of \fBif, case\fP
624: and \fBfor\fP constructions is given in
625: section 2.10\|.
626: .LP
627: A multiple test \fBif\fP command
628: of the form
629: .DS
630: if \*(ZZ
631: then \*(ZZ
632: else if \*(ZZ
633: then \*(ZZ
634: else if \*(ZZ
635: \*(ZZ
636: fi
637: fi
638: fi
639: .DE
640: may be written using an extension of the \fBif\fP
641: notation as,
642: .DS
643: if \*(ZZ
644: then \*(ZZ
645: elif \*(ZZ
646: then \*(ZZ
647: elif \*(ZZ
648: \*(ZZ
649: fi
650: .DE
651: .LP
652: The following example is the \fItouch\fP command
653: which changes the `last modified' time for a list
654: of files.
655: The command may be used in conjunction
656: with \fImake\fP (1) to force recompilation of a list
657: of files.
658: .DS
659: flag=
660: for i
661: do case $i in
662: \*(DC\(mic) flag=N ;;
663: \*(DC\*(ST) if test \(mif $i
664: \*(DC then ln $i junk$$; rm junk$$
665: \*(DC elif test $flag
666: \*(DC then echo file \\\\\'$i\\\\\' does not exist
667: \*(DC else >$i
668: \*(DC fi
669: \*(DO esac
670: done
671: .DE
672: The \fB\(mic\fP flag is used in this command to
673: force subsequent files to be created if they do not already exist.
674: Otherwise, if the file does not exist, an error message is printed.
675: The shell variable \fIflag\fP
676: is set to some non-null string if the \fB\(mic\fP
677: argument is encountered.
678: The commands
679: .DS
680: ln \*(ZZ; rm \*(ZZ
681: .DE
682: make a link to the file and then remove it
683: thus causing the last modified date to be updated.
684: .LP
685: The sequence
686: .DS
687: if command1
688: then command2
689: fi
690: .DE
691: may be written
692: .DS
693: command1 && command2
694: .DE
695: Conversely,
696: .DS
697: command1 \*(VT\*(VT command2
698: .DE
699: executes \fIcommand2\fP only if \fIcommand1\fP
700: fails.
701: In each case the value returned
702: is that of the last simple command executed.
703: .SH
704: 2.8\ Command\ grouping
705: .LP
706: Commands may be grouped in two ways,
707: .DS
708: \fB{\fI command-list\fB ; }\fR
709: .DE
710: and
711: .DS
712: \fB(\fI command-list\fB )\fR
713: .DE
714: .LP
715: In the first \fIcommand-list\fP is simply executed.
716: The second form executes \fIcommand-list\fP
717: as a separate process.
718: For example,
719: .DS
720: (cd x; rm junk )
721: .DE
722: executes \fIrm junk\fP in the directory
723: \fBx\fP without changing the current
724: directory of the invoking shell.
725: .LP
726: The commands
727: .DS
728: cd x; rm junk
729: .DE
730: have the same effect but leave the invoking
731: shell in the directory \fBx.\fP
732: .SH
733: 2.9\ Debugging\ shell\ procedures
734: .LP
735: The shell provides two tracing mechanisms
736: to help when debugging shell procedures.
737: The first is invoked within the procedure
738: as
739: .DS
740: set \(miv
741: .DE
742: (\fBv\fP for verbose) and causes lines of the
743: procedure to be printed as they are read.
744: It is useful to help isolate syntax errors.
745: It may be invoked without modifying the procedure
746: by saying
747: .DS
748: sh \(miv proc \*(ZZ
749: .DE
750: where \fIproc\fP is the name of the shell procedure.
751: This flag may be used in conjunction
752: with the \fB\(min\fP flag which prevents
753: execution of subsequent commands.
754: (Note that saying \fIset \(min\fP at a terminal
755: will render the terminal useless
756: until an end-of-file is typed.)
757: .LP
758: The command
759: .DS
760: set \(mix
761: .DE
762: will produce an execution
763: trace.
764: Following parameter substitution
765: each command is printed as it is executed.
766: (Try these at the terminal to see
767: what effect they have.)
768: Both flags may be turned off by saying
769: .DS
770: set \(mi
771: .DE
772: and the current setting of the shell flags is available as \fB$\(mi\|.\fR
773: .SH
774: 2.10\ The\ man\ command
775: .LP
776: The following is the \fIman\fP command
777: which is used to diplay sections of the UNIX manual on your terminal.
778: It is called, for example, as
779: .DS
780: man sh
781: man \(mit ed
782: man 2 fork
783: .DE
784: In the first the manual section for \fIsh\fP
785: is displayed..
786: Since no section is specified, section 1 is used.
787: The second example will typeset (\fB\(mit\fP option)
788: the manual section for \fIed.\fP
789: The last prints the \fIfork\fP manual page
790: from section 2, which covers system calls.
791: .sp 2
792: .DS
793: cd /usr/man
794:
795: : \'colon is the comment command\'
796: : \'default is nroff ($N), section 1 ($s)\'
797: N=n\ s=1
798:
799: for i
800: do case $i in
801: .sp .5
802: \*(DC[1\(mi9]\*(ST) s=$i ;;
803: .sp .5
804: \*(DC\(mit) N=t ;;
805: .sp .5
806: \*(DC\(min) N=n ;;
807: .sp .5
808: \*(DC\(mi\*(ST) echo unknown flag \\\\\'$i\\\\\' ;;
809: .sp .5
810: \*(DC\*(ST) if test \(mif man$s/$i.$s
811: \*(DC then ${N}roff man0/${N}aa man$s/$i.$s
812: \*(DC else : \'look through all manual sections\'
813: \*(DC found=no
814: \*(DC for j in 1 2 3 4 5 6 7 8 9
815: \*(DC do if test \(mif man$j/$i.$j
816: \*(DC \*(DOthen man $j $i
817: \*(DC \*(DO\*(THfound=yes
818: \*(DC \*(DOfi
819: \*(DC done
820: \*(DC case $found in
821: \*(DC \*(Cano) echo \\'$i: manual page not found\\'
822: \*(DC esac
823: \*(DC fi
824: \*(DOesac
825: done
826: .DE
827: .ce
828: .ft B
829: Figure 1. A version of the man command
830: .ft R
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.