|
|
1.1 ! root 1: .so ../ADM/mac ! 2: .XX rc 283 "Rc \(em A Shell for Plan 9 and UNIX" ! 3: .fp 5 T CW \" T for Typewriter ! 4: .Tm shell programming language g ! 5: .de TP \" An indented paragraph describing some command, tagged with the command name ! 6: .IP "\\fT\\$1\\fR" 5 ! 7: .if \\w'\\fT\\$1\\fR'-4n .br ! 8: .. ! 9: .de CI ! 10: .nr Sf \\n(.f ! 11: \%\&\\$3\f(CW\\$1\fI\&\\$2\f\\n(Sf ! 12: .. ! 13: .TL ! 14: Rc \(em A Shell for Plan 9 and UNIX ! 15: .AU ! 16: Tom Duff ! 17: .AI ! 18: .MH ! 19: .AB ! 20: .I Rc ! 21: is a command interpreter for Plan 9. ! 22: It also runs on a variety of UNIX systems, ! 23: including SunOS and the Tenth Edition. ! 24: It provides similar facilities to Bourne's ! 25: .I /bin/sh , ! 26: with some small additions and mostly less idiosyncratic syntax. ! 27: This paper introduces ! 28: .I rc ! 29: with numerous examples, and discusses its design and ! 30: why it varies from Bourne's. ! 31: .AE ! 32: .2C ! 33: .NH ! 34: Introduction ! 35: .PP ! 36: Plan 9 needs a command-programming language. As porting the ! 37: Bourne shell to a non-UNIX environment seemed a daunting task, ! 38: I chose to write a new command interpreter, called ! 39: .I rc ! 40: because it runs commands. ! 41: Although tinkering with perfection is a dangerous business, ! 42: I could hardly resist trying to `improve' on Bourne's design. ! 43: Thus, ! 44: .I rc ! 45: is similar in spirit, but different in detail from Bourne's ! 46: shell. ! 47: .NH ! 48: Simple commands ! 49: .PP ! 50: For the simplest uses, ! 51: .I rc ! 52: has syntax familiar to Bourne shell users. ! 53: A simple command is a blank-separated sequence of arguments. ! 54: .P1 ! 55: date ! 56: .P2 ! 57: prints the current date and time, and ! 58: .P1 ! 59: con alice ! 60: .P2 ! 61: connects the user's terminal to the machine ! 62: .CW alice . ! 63: .NH ! 64: Quotation ! 65: .PP ! 66: An argument that contains a space or one of ! 67: .I rc 's ! 68: other syntax characters should be enclosed in apostrophes ! 69: .CW ' ). ( ! 70: For example: ! 71: .P1 ! 72: rm 'odd file name' ! 73: .P2 ! 74: To include an apostrophe in a quoted name, it must be doubled: ! 75: .P1 ! 76: echo 'How''s your father?' ! 77: .P2 ! 78: .NH ! 79: Comments and continuation ! 80: .PP ! 81: A number-sign ! 82: .CW # ) ( ! 83: and all characters following it up to, but not including, the next newline ! 84: are ignored, except in quotation marks. ! 85: .PP ! 86: A long command line may be continued on subsequent lines by typing a ! 87: backslash ! 88: .CW \e ) ( ! 89: followed immediately by a newline, anywhere that white space is required. ! 90: Commands also continue onto the next line when the last symbol on ! 91: a line could not reasonably be the end of the command. ! 92: .NH ! 93: I/O Redirection ! 94: .PP ! 95: Many commands write output on the standard output file, normally the terminal. ! 96: A command's standard output may be made to overwrite a file by writing ! 97: .P1 ! 98: who >user.names ! 99: .P2 ! 100: This command produces a list of the currently logged in users in a file named ! 101: .CW user.names . ! 102: Standard output may be appended to the end of a file by ! 103: .P1 ! 104: who >>user.names ! 105: .P2 ! 106: In either case, mentioning a non-existent file causes it to be created. ! 107: .PP ! 108: Likewise, a command's standard input, also normally the terminal, may be connected to ! 109: a file by ! 110: .P1 ! 111: wc <file ! 112: .P2 ! 113: This command will report the number of characters, lines and words in ! 114: .CW file . ! 115: ........ ! 116: .NH ! 117: Pipelines ! 118: .PP ! 119: The standard output of one command may be connected to the standard input of another ! 120: command like this: ! 121: .P1 ! 122: who | wc ! 123: .P2 ! 124: This prints the number of users currently logged in, and is equivalent to ! 125: .P1 ! 126: who >tmp ! 127: wc <tmp ! 128: .P2 ! 129: except that no temporary file is produced. Instead a pipe \(em an ! 130: interprocess channel that looks to one process like an output file and to ! 131: another like an input file \(em is created joining the two commands, which ! 132: run simultaneously. The pipe contains a data buffer so that the two ! 133: commands need not produce and consume data in perfect lock-step. ! 134: .NH ! 135: Filename patterns ! 136: .PP ! 137: .I Rc ! 138: has several ways to generate argument lists automatically. ! 139: These include filename pattern matching, variable substitution, string concatenation, ! 140: command substitution and pipeline branching. ! 141: .PP ! 142: Any literal word containing one of the meta-characters ! 143: .CW * , ! 144: .CW ? ! 145: or ! 146: .CW [ ! 147: is a pattern used to match filenames. ! 148: A ! 149: .CW * ! 150: matches any sequence of characters ! 151: a ! 152: .CW ? ! 153: matches any single character, ! 154: and a list of characters between ! 155: .CW [ ! 156: and ! 157: .CW ] ! 158: matches a single character from the listed set. ! 159: The list may include ranges like ! 160: .CW a-z , ! 161: specifying all ASCII characters between the two. ! 162: The entire set is complemented if the first character ! 163: after ! 164: .CW [ ! 165: is ! 166: .CW ~ ! 167: (a tilde.) ! 168: No meta-character can match ! 169: the first character of the filenames ! 170: .CW . ! 171: and ! 172: .CW .. ! 173: or the character ! 174: .CW / . ! 175: .PP ! 176: A pattern is replaced by a list of all the names that it matches. ! 177: If it matches no name, it remains unreplaced. ! 178: .PP ! 179: Meta-characters are active only when they appear literally ! 180: and unquoted. For example, if a variable (see below) has a ! 181: .CW * ! 182: in it, and the value is substituted into a line, it is ! 183: not used for filename matching. ! 184: .NH ! 185: Variables ! 186: .PP ! 187: .I Rc ! 188: provides variables whose values are lists of arguments. ! 189: Variables may be given values by typing, for example: ! 190: .P1 ! 191: path=(. /bin /usr/bin) ! 192: user=td ! 193: tty=/dev/tty8 ! 194: .P2 ! 195: The parentheses indicate that the value assigned to ! 196: .CW path ! 197: is a list of three strings. The variables ! 198: .CW user ! 199: and ! 200: .CW tty ! 201: are assigned lists containing a single string. ! 202: .PP ! 203: The value of a variable can be substituted into a command by ! 204: preceding its name with a ! 205: .CW $ , ! 206: like this: ! 207: .P1 ! 208: echo $path ! 209: .P2 ! 210: If ! 211: .CW path ! 212: had been set as above, this would be equivalent to ! 213: .P1 ! 214: echo . /bin /usr/bin ! 215: .P2 ! 216: Variables may be subscripted by numbers or lists of numbers, ! 217: like this: ! 218: .P1 ! 219: echo $path(2) ! 220: echo $path(3 2 1) ! 221: .P2 ! 222: These are equivalent to ! 223: .P1 ! 224: echo /bin ! 225: echo /usr/bin /bin . ! 226: .P2 ! 227: There can be no space separating the variable's name from the ! 228: left parenthesis. Otherwise, the subscript would be considered ! 229: a separate parenthesized list. ! 230: .PP ! 231: The number of strings in a variable can be determined by the ! 232: .CW $# ! 233: operator. For example, ! 234: .P1 ! 235: echo $#path ! 236: .P2 ! 237: would print the number of entries in ! 238: .CW $path . ! 239: .PP ! 240: The following two assignments are subtly different: ! 241: .P1 ! 242: empty=() ! 243: null='' ! 244: .P2 ! 245: The first sets ! 246: .CW empty ! 247: to a list containing no strings. ! 248: The second sets ! 249: .CW null ! 250: to a list containing a single string, ! 251: but the string contains no characters. ! 252: .PP ! 253: Although these may seem like more or less ! 254: the same thing (in Bourne's shell, they are ! 255: indistinguishable), they behave differently ! 256: in almost all circumstances. ! 257: Among other things ! 258: .P1 ! 259: echo $#empty ! 260: .P2 ! 261: prints 0, whereas ! 262: .P1 ! 263: echo $#null ! 264: .P2 ! 265: prints 1. ! 266: .PP ! 267: All variables that have never been set have the value ! 268: .CW () . ! 269: ...... ! 270: .NH ! 271: Arguments ! 272: .PP ! 273: When ! 274: .I rc ! 275: is reading its input from a file, the file has access ! 276: to the arguments supplied on ! 277: .I rc 's ! 278: command line. The variable ! 279: .CW $* ! 280: initially has the list of arguments assigned to it. ! 281: The names ! 282: .CW $1 , ! 283: .CW $2 , ! 284: etc. are synonyms for ! 285: .CW $*(1) , ! 286: .CW $*(2) , ! 287: etc. ! 288: In addition, ! 289: .CW $0 ! 290: is the name of the file from which ! 291: .I rc 's ! 292: input is being read. ! 293: .PP ! 294: The built-in ! 295: .CW shift ! 296: command deletes the first member of ! 297: .CW $* . ! 298: If ! 299: .CW shift ! 300: is given an argument, it deletes the given ! 301: number of members from ! 302: .CW $*. ! 303: Thus, ! 304: .P1 ! 305: *=(Never, ever type rm -fr /) ! 306: shift 2 ! 307: echo Please $* ! 308: .P2 ! 309: would print ! 310: .P1 ! 311: Please type rm -fr / ! 312: .P2 ! 313: .NH ! 314: Concatenation ! 315: .PP ! 316: .I Rc ! 317: has a string concatenation operator, the caret ! 318: .CW ^ , ! 319: to build a arguments out of pieces. ! 320: .P1 ! 321: echo hully^gully ! 322: .P2 ! 323: is exactly equivalent to ! 324: .P1 ! 325: echo hullygully ! 326: .P2 ! 327: Suppose variable ! 328: .CW i ! 329: contains the name of a command. ! 330: Then ! 331: .P1 ! 332: cc -o $i $i^.c ! 333: .P2 ! 334: might compile the command's source code, leaving the ! 335: result in the appropriate file. ! 336: .PP ! 337: Concatenation distributes over lists. The following ! 338: .P1 ! 339: echo (a b c)^(1 2 3) ! 340: src=(main subr io) ! 341: cc $src^.c ! 342: .P2 ! 343: are equivalent to ! 344: .P1 ! 345: echo a1 b2 c3 ! 346: cc main.c subr.c io.c ! 347: .P2 ! 348: In detail, the rule is: if both operands of ! 349: .CW ^ ! 350: are lists of the same non-zero number of strings, they are concatenated ! 351: pairwise. Otherwise, if one of the operands is a single string, ! 352: it is concatenated with each member of the other operand in turn. ! 353: Any other combination of operands is an error. ! 354: .NH ! 355: Free carets ! 356: .PP ! 357: User demand has dictated that ! 358: .I rc ! 359: insert carets in certain places, to make the syntax ! 360: look more like the Bourne shell. For example, this: ! 361: .P1 ! 362: cc -$flags $stems.c ! 363: .P2 ! 364: is equivalent to ! 365: .P1 ! 366: cc -^$flags $stems^.c ! 367: .P2 ! 368: In general, ! 369: .I rc ! 370: will insert ! 371: .CW ^ ! 372: between two arguments that are not separated by white space. ! 373: Specifically, whenever one of ! 374: .CW "$'` ! 375: follows a quoted or unquoted word, or an unquoted word follows ! 376: a quoted word with no intervening blanks or tabs, a ! 377: .CW ^ ! 378: is inserted between the two. If an unquoted word immediately following a ! 379: .CW $ ! 380: contains a character other than an alphanumeric, underscore or ! 381: .CW * , ! 382: a ! 383: .CW ^ ! 384: is inserted before the first such character. ! 385: .NH ! 386: Command substitution ! 387: .PP ! 388: It is often useful to build an argument list from the output of a command. ! 389: .I Rc ! 390: allows a command, enclosed in braces and preceded by a left quote, ! 391: .CW "`{...}" , ! 392: anywhere that an argument is required. The command is executed and its ! 393: standard output captured. ! 394: The characters stored in the variable ! 395: .CW ifs ! 396: are used to split the output into arguments. ! 397: For example, ! 398: .P1 ! 399: cat `{ls -tr|sed 10q} ! 400: .P2 ! 401: will catenate the ten oldest files in the current directory in temporal order. ! 402: .NH ! 403: Pipeline branching ! 404: .PP ! 405: The pipeline notation described above is general enough for almost all cases. ! 406: Very occasionally it is useful to have pipelines that are not linear. ! 407: Pipeline topologies more general than trees can require arbitrarily large pipe buffers, ! 408: or worse, can cause deadlock. ! 409: .I Rc ! 410: has syntax for some kinds of non-linear but treelike pipelines. ! 411: For example, ! 412: .P1 ! 413: cmp <{old} <{new} ! 414: .P2 ! 415: will regression test a new version of a command. ! 416: A ! 417: .CW < ! 418: (or ! 419: .CW > ) ! 420: followed by a command in braces causes the command to be run with ! 421: its standard output (or input) attached to a pipe. The parent command ! 422: .CW cmp "" ( ! 423: in the example) ! 424: is started with the other end of the pipe attached to some file descriptor ! 425: or other, and with an argument that will connect to the pipe when opened ! 426: (e.g. ! 427: .CW /dev/fd/6 .) ! 428: On systems without ! 429: .CW /dev/fd , ! 430: or something similar (SunOS for example) this feature does not work. ! 431: ..... ! 432: .NH ! 433: Exit status ! 434: .PP ! 435: When a command exits, it returns status to the program that executed it. ! 436: On UNIX, status is a small positive number, with zero indicating normal termination ! 437: and non-zero values encoding error conditions (in a non-standard way). If a ! 438: UNIX command terminates abnormally rather than by executing ! 439: .CW exit (2), ! 440: .I rc ! 441: takes the status to be 1000 plus the termination status provided to ! 442: .CW wait (2). ! 443: On Plan 9 status is a character string describing an error condition. ! 444: On normal termination it is empty. ! 445: .PP ! 446: .I Rc ! 447: captures commands' exit statuses in the variable ! 448: .CW $status . ! 449: For a simple command, the value of ! 450: .CW $status ! 451: is just as described above. For a pipeline, ! 452: .CW $status ! 453: is set to the concatenation of the statuses of the pipeline components, ! 454: with ! 455: .CW | ! 456: characters for separators. ! 457: .PP ! 458: .I Rc ! 459: has a number of command forms that various kinds of control flow, ! 460: many of them conditioned by the status returned from previously ! 461: executed commands. In all cases, any ! 462: .CW $status ! 463: containing only ! 464: .CW 0 's ! 465: and ! 466: .CW | 's ! 467: has boolean value ! 468: .I true . ! 469: Any other status is ! 470: .I false . ! 471: .NH ! 472: Flow of control ! 473: .PP ! 474: .I Rc ! 475: will accept multiple commands on a line, separated by ! 476: .CW & ! 477: or ! 478: .CW ; . ! 479: A command followed by ! 480: .CW & ! 481: is executed asynchronously \(em ! 482: .I rc ! 483: does not wait for it to exit, and it ! 484: disconnects its standard input from the terminal, ! 485: redirecting it to ! 486: .CW /dev/null ! 487: so that the command and ! 488: .I rc ! 489: do not compete for input lines. ! 490: The process id of an asynchronous command is stored in the variable ! 491: .CW $apid , ! 492: and if ! 493: .I rc ! 494: is running interactively (that is, its input is coming from a terminal), ! 495: the process id is printed when the command starts. ! 496: .PP ! 497: Commands separated by ! 498: .CW ; ! 499: are executed in sequence, but ! 500: .I rc ! 501: waits for the first command to terminate before starting the second. ! 502: Thus ! 503: .P1 ! 504: fortune;fortune& ! 505: .P2 ! 506: prints out two fortunes (and a process id), not waiting for the ! 507: second to appear before prompting for more commands. ! 508: .NH ! 509: Command grouping ! 510: .PP ! 511: A sequence of commands enclosed in ! 512: .CW {} ! 513: may be used anywhere a command is required. ! 514: For example: ! 515: .P1 ! 516: {sleep 3600;echo 'Time''s up!'}& ! 517: .P2 ! 518: will wait an hour in the background, then print a message. ! 519: Without the braces: ! 520: .P1 ! 521: sleep 3600;echo 'Time''s up!'& ! 522: .P2 ! 523: this would lock up the terminal for an hour, ! 524: then print the message in the background! ! 525: .NH ! 526: Conditional execution \(em \f(CW&&\fP and \f(CW||\fP ! 527: .PP ! 528: A pair of commands may be separated by ! 529: .CW && ! 530: or ! 531: .CW || . ! 532: In either case, the first command is executed and its ! 533: status examined. ! 534: If the operator is ! 535: .CW && ! 536: and the status is ! 537: .I true , ! 538: the second command is executed. ! 539: If the operator is ! 540: .CW || ! 541: the status must be ! 542: .I false ! 543: to execute the second command. ! 544: Thus ! 545: .P1 ! 546: cyntax *.c && cc -g -o cmd *.c ! 547: .P2 ! 548: compiles ! 549: .CW cmd ! 550: only if ! 551: .CW cyntax ! 552: passes on it, and ! 553: .P1 ! 554: {sleep 86400;rm -r /junk} || ! 555: echo Failure!|mail td & ! 556: .P2 ! 557: waits 24 hours, then tries to remove all files in ! 558: .CW /junk . ! 559: On failure it sends me mail. It does all of this in ! 560: the background, so I can use my terminal for something ! 561: else in the interim. ! 562: .NH ! 563: Subshells ! 564: .PP ! 565: The ! 566: .CW @ ! 567: operator executes the following command in a new process. ! 568: This is useful primarily to insulate the parent process ! 569: from the effects of built-in commands, like this ! 570: .P1 ! 571: @ {cd /elsewhere;tar cf - .} | ! 572: tar -xf - ! 573: .P2 ! 574: This dubious but venerated idiom copies ! 575: the contents of ! 576: .CW /elsewhere ! 577: to the current directory by building a ! 578: .CW tar ! 579: file on standard output and immediately ! 580: cracking it at the other end of a pipe. ! 581: The first ! 582: .CW tar ! 583: runs in ! 584: .CW /elsewhere , ! 585: but, because of the ! 586: .CW @ , ! 587: the second operates in the original directory. ! 588: .NH ! 589: Control flow \(em \f(CWfor\fP ! 590: .PP ! 591: A command may be executed once for each member of a list ! 592: by typing, for example: ! 593: .P1 ! 594: for(i in printf scanf putchar) ! 595: look $i /usr/td/lib/dw.dat ! 596: .P2 ! 597: This looks for each of the words ! 598: .CW printf , ! 599: .CW scanf ! 600: and ! 601: .CW putchar ! 602: in the given file. ! 603: The general form is ! 604: .P1 ! 605: for(\fIname\fP in \fIlist\fP) ! 606: \fIcommand\fP ! 607: .P2 ! 608: or ! 609: .P1 ! 610: for(\fIname\fP) ! 611: \fIcommand\fP ! 612: .P2 ! 613: In the first case, ! 614: .I command ! 615: is executed once for each member of ! 616: .I list , ! 617: with that member assigned to variable ! 618: .I name . ! 619: If ! 620: .CI in " list ! 621: is not given, ! 622: .I $* ! 623: is used. ! 624: .NH ! 625: Conditional execution \(em \f(CWif\fP ! 626: .PP ! 627: .I Rc ! 628: also provides a general if-statement. For example: ! 629: .P1 ! 630: if(cyntax *.c) ! 631: cc -g -o cmd *.c ! 632: .P2 ! 633: is equivalent to the similar example above. ! 634: An `if not' statement provides a two-tailed conditional. ! 635: For example: ! 636: .P1 ! 637: for(i){ ! 638: if(test -f /tmp/$i) ! 639: echo $i already in /tmp ! 640: if not ! 641: cp $i /tmp ! 642: } ! 643: .P2 ! 644: This loops over each file in ! 645: .CW $* , ! 646: copying to ! 647: .CW /tmp ! 648: those that do not already appear there, and ! 649: printing a message for those that do. ! 650: .NH ! 651: Control flow \(em \f(CWwhile\fP ! 652: .PP ! 653: .I Rc 's ! 654: while statement looks like this: ! 655: .P1 ! 656: while(newer subr.c subr.o) sleep 5 ! 657: .P2 ! 658: This waits until ! 659: .CW subr.o ! 660: is newer than ! 661: .CW subr.c ! 662: (presumably because the C compiler finished with it.) ! 663: .NH ! 664: Control flow \(em \f(CWswitch\fP ! 665: .PP ! 666: .I Rc ! 667: provides a switch statement to do pattern-matching on ! 668: arbitrary strings. Its general form is ! 669: .P1 ! 670: switch(\fIword\fP){ ! 671: case \fIpattern ...\fP ! 672: \fIcommands\fP ! 673: case \fIpattern ...\fP ! 674: \fIcommands\fP ! 675: ... ! 676: } ! 677: .P2 ! 678: .I Rc ! 679: attempts to match the word against the patterns in each case statement in turn. ! 680: Patterns are the same as for filename matching, except that ! 681: .CW / ! 682: and the first characters of ! 683: .CW . ! 684: and ! 685: .CW .. ! 686: need not be matched explicitly. ! 687: .PP ! 688: If any pattern matches, the ! 689: commands following that case up to ! 690: the next case (or the end of the switch) ! 691: are executed, and execution of the switch ! 692: is complete. For example, ! 693: .P1 ! 694: switch($#*){ ! 695: case 1 ! 696: cat >>$1 ! 697: case 2 ! 698: cat >>$2 <$1 ! 699: case * ! 700: echo 'Usage: append [from] to' ! 701: } ! 702: .P2 ! 703: is an append command. Called with one file argument, ! 704: it tacks standard input to its end. With two, the ! 705: first is appended to the second. Any other number ! 706: elicits a usage message. ! 707: .PP ! 708: The built-in ! 709: .CW ~ ! 710: command also matches patterns, and is often more concise than a switch. ! 711: Its arguments are a string and a list of patterns. It sets ! 712: .CW $status ! 713: to zero if and only if any of the patterns matches the string. ! 714: The following example processes option arguments for the ! 715: .I man (1) ! 716: command: ! 717: .P1 ! 718: opt=() ! 719: while(~ $1 -* [1-9] 10){ ! 720: switch($1){ ! 721: case [1-9] 10 ! 722: sec=$1 secn=$1 ! 723: case -f ! 724: c=f s=f ! 725: case -[qwnt] ! 726: cmd=$1 ! 727: case -T* ! 728: T=$1 ! 729: case -* ! 730: opt=($opt $1) ! 731: } ! 732: shift ! 733: } ! 734: .P2 ! 735: .NH ! 736: Functions ! 737: .PP ! 738: Functions may be defined by typing ! 739: .P1 ! 740: fn \fIname\fP { \fIcommands\fP } ! 741: .P2 ! 742: Subsequently, whenever a command named ! 743: .I name ! 744: is encountered, the remainder of the command's ! 745: argument list will assigned to ! 746: .CW $* ! 747: and ! 748: .I rc ! 749: will execute the ! 750: .I commands . ! 751: The value of ! 752: .CW $* ! 753: will be restored on completion. ! 754: For example: ! 755: .P1 ! 756: fn g { ! 757: gre -e $1 *.[hcyl] ! 758: } ! 759: .P2 ! 760: defines ! 761: .CI g " pattern ! 762: to look for occurrences of ! 763: .I pattern ! 764: in all program source files in the current directory. ! 765: .PP ! 766: Function definitions are deleted by writing ! 767: .P1 ! 768: fn \fIname\fP ! 769: .P2 ! 770: with no function body. ! 771: ..... ! 772: .NH ! 773: Command execution ! 774: .PP ! 775: Up to now we've said very little about what ! 776: .I rc ! 777: does to execute a simple command. ! 778: If the command name is the name of a function defined using ! 779: .CW fn , ! 780: the function is executed. ! 781: Otherwise, if it is the name of a built-in command, the ! 782: built-in is executed directly by ! 783: .I rc . ! 784: Otherwise, if the name contains a ! 785: .CW / , ! 786: it is taken to be the name of a binary program ! 787: and is executed using ! 788: .I exec (2). ! 789: If the name contains no ! 790: .CW / , ! 791: then directories mentioned in the variable ! 792: .CW $path ! 793: are searched until an executable file is found. ! 794: .NH ! 795: Built-in commands ! 796: .PP ! 797: Several commands are executed internally by ! 798: .I rc , ! 799: usually because their execution changes or depends on ! 800: .I rc 's ! 801: internal state. ! 802: .TP ". [-i] \fIfile ...\fT ! 803: Execute commands from ! 804: .I file . ! 805: .CW $* ! 806: is set for the duration to the reminder of the argument list following ! 807: .I file . ! 808: .CW $path ! 809: is used to search for ! 810: .I file . ! 811: Option ! 812: .CW -i ! 813: indicates interactive input \(mi a prompt ! 814: (found in ! 815: .CW $prompt ) ! 816: is printed before each command is read. ! 817: .TP "builtin \fIcommand ...\fT ! 818: Execute ! 819: .I command ! 820: as usual except that any function named ! 821: .I command ! 822: is ignored. ! 823: For example, ! 824: .P1 ! 825: fn cd{ ! 826: builtin cd $* && pwd ! 827: } ! 828: .P2 ! 829: defines a replacement for the ! 830: .CW cd ! 831: built-in (see below) that announces the full name of the new directory. ! 832: .TP "cd [\fIdir\fT] ! 833: Change the current directory to ! 834: .I dir . ! 835: The default argument is ! 836: .CW $home . ! 837: .CW $cdpath ! 838: is a list of places in which to search for ! 839: .I dir . ! 840: .TP "eval [\fIarg ...\fT] ! 841: The arguments are concatenated separated by spaces into a string, read as input to ! 842: .I rc , ! 843: and executed. For example, ! 844: .P1 ! 845: x='$y' ! 846: y=Doody ! 847: eval echo Howdy, $x ! 848: .P2 ! 849: would echo ! 850: .P1 ! 851: Howdy, Doody ! 852: .P2 ! 853: since arguments of ! 854: .CW eval ! 855: would be ! 856: .P1 ! 857: Howdy, $y ! 858: .P2 ! 859: .TP "exec \fIcommand ...\fT ! 860: .I Rc ! 861: replaces itself with the given non-built-in ! 862: .I command . ! 863: .TP "exit [\fIstatus\fP] ! 864: Exit with the given status. If none is given, the current value of ! 865: .CW $status ! 866: is used. ! 867: .TP finit ! 868: Initialize functions imported from the environment. ! 869: Intended for use only by ! 870: .I rc 's ! 871: initialization procedure. ! 872: Currently this is non-functional on Plan 9, as no ! 873: means of environmental function-storage yet exists. ! 874: .TP "flag \fIletter\fP" ! 875: Sets ! 876: .CW $status ! 877: to zero if and only if ! 878: .I rc ! 879: was invoked with option ! 880: .CI - letter ! 881: set. Intended for use by ! 882: .I rc 's ! 883: initialization procedure. ! 884: .TP "mount \fInew old\fT ! 885: (Plan 9 only.) ! 886: Mount the name ! 887: .I new ! 888: on ! 889: .I old . ! 890: .TP "shift [\fIn\fT] ! 891: Delete the first ! 892: .I n ! 893: (default 1) elements of ! 894: .CW $* . ! 895: .TP "umask [\fIoctal\fP] ! 896: (UNIX only.) Set ! 897: .I rc 's ! 898: file creation mask to the given octal value. ! 899: If no value is given, the current mask value is printed. ! 900: .TP "unmount [\fInew\fT] \fIold ! 901: (Plan 9 only.) ! 902: Unmount the name ! 903: .I old . ! 904: If ! 905: .I new ! 906: is given, unmount ! 907: .I old ! 908: from ! 909: .I new . ! 910: .TP "wait [\fIpid\fP] ! 911: Wait for the process with the given ! 912: .I pid ! 913: to exit. If no ! 914: .I pid ! 915: is given, all outstanding processes are waited for. ! 916: .TP "whatis \fIname ...\fT ! 917: Print the value of each ! 918: .I name ! 919: in a form suitable for input to ! 920: .I rc . ! 921: The output is an assignment to any variable, the definition of any function, ! 922: a call to ! 923: .CW builtin ! 924: for any built-in command, or the full path name of any binary program. ! 925: For example, ! 926: .P1 ! 927: whatis path g cd who ! 928: .P2 ! 929: might print ! 930: .P1 ! 931: path=(. /bin /usr/bin) ! 932: fn g {gre -e $1 *.[hycl]} ! 933: builtin cd ! 934: /bin/who ! 935: .P2 ! 936: .TP "~ \fIsubject pattern ... ! 937: The ! 938: .I subject ! 939: is matched against each ! 940: .I pattern ! 941: in turn. On a match, ! 942: .CW $status ! 943: is set to zero. ! 944: Otherwise, it is set to one. ! 945: Patterns are the same as for filename matching, ! 946: except that ! 947: .CW / ! 948: and the first character of ! 949: .CW . ! 950: and ! 951: .CW .. ! 952: need not be matched explicitly. ! 953: The ! 954: .I patterns ! 955: are not subjected to filename replacement before the ! 956: .CW ~ ! 957: command is executed, so they need not be enclosed in ! 958: quotation marks, unless of course, a literal match for ! 959: .CW * ! 960: .CW [ ! 961: or ! 962: .CW ? ! 963: is required. ! 964: For example ! 965: .P1 ! 966: ~ $1 ? ! 967: .P2 ! 968: matches any single character, whereas ! 969: .P1 ! 970: ~ $1 '?' ! 971: .P2 ! 972: only matches a literal question mark. ! 973: .NH ! 974: Special variables ! 975: .PP ! 976: Several variables are set internally by ! 977: .I rc ! 978: or used to guide its execution. ! 979: .TP $* ! 980: Set to ! 981: .I rc 's ! 982: argument list during initialization. ! 983: A ! 984: .CW . ! 985: command or function execution saves ! 986: .CW $* ! 987: on a stack and sets it to the new argument list. The saved ! 988: value is restored on completion. ! 989: .TP $apid ! 990: Whenever a process is started asynchronously with ! 991: .CW & , ! 992: .CW $apid ! 993: receives its process id. ! 994: .TP $cflag ! 995: Set to the string provided on ! 996: .I rc 's ! 997: command line with the ! 998: .CW -c ! 999: option, if any. This is provided for the ! 1000: use of ! 1001: .I rc's initialization procedure. ! 1002: .TP $home ! 1003: The default directory for ! 1004: .CW cd . ! 1005: On UNIX, if ! 1006: .CW $home ! 1007: is not initially set, and ! 1008: .CW $HOME ! 1009: is, then ! 1010: .CW $home ! 1011: is set to ! 1012: .CW $HOME . ! 1013: .TP $ifs ! 1014: The input field separators used in command substitution. ! 1015: If not set in ! 1016: .I rc 's ! 1017: environment, it is initialized to blank, tab and newline. ! 1018: .TP $path ! 1019: The search path used to find commands and input files for the ! 1020: .CW . ! 1021: command. ! 1022: If not set in the environment, it is initialized to ! 1023: .CW "(. /bin /usr/bin) ! 1024: on UNIX, ! 1025: .CW "(. /bin) ! 1026: on Plan 9. ! 1027: .TP $pid ! 1028: Set during initialization to ! 1029: .I rc 's ! 1030: process id. ! 1031: .TP $prompt ! 1032: When ! 1033: .I rc ! 1034: is run interactively, the first member of ! 1035: .CW $prompt ! 1036: is printed before reading each command. ! 1037: The second member is printed if ! 1038: .I rc ! 1039: expects a command to be continued on another line. ! 1040: If not set in the environment, ! 1041: .I rc ! 1042: initializes it to ! 1043: .CW "('% ' ' ')" . ! 1044: .TP $status ! 1045: On UNIX, this is set to the low 8 bits of the ! 1046: .I exit (2) ! 1047: argument of a normally terminating binary (unless started with ! 1048: .CW & ), ! 1049: or to 1000 plus the termination status on abnormal termination. ! 1050: On Plan 9, ! 1051: .CW $status ! 1052: is set to the process's termination message. ! 1053: On either system, the statuses of all processes in a pipeline ! 1054: are captured and concatenated, separated by ! 1055: .CW | ! 1056: characters. ! 1057: .CW ! ! 1058: and ! 1059: .CW ~ ! 1060: also set ! 1061: .CW $status . ! 1062: Its value is used to control execution in ! 1063: .CW && , ! 1064: .CW || , ! 1065: .CW if ! 1066: and ! 1067: .CW while ! 1068: commands. ! 1069: When ! 1070: .I rc ! 1071: exits at end-of-file of its input or on executing an ! 1072: .CW exit ! 1073: command with no argument, ! 1074: .CW $status ! 1075: is its exit status. ! 1076: (This is only strictly true on Plan 9. On UNIX, the exit status ! 1077: must be numeric. Therefore, if the value of ! 1078: .CW $status ! 1079: contains ! 1080: .CW | ! 1081: characters, they are deleted before converting it to a number, and if ! 1082: .CW $status ! 1083: contains other non-numeric characters, ! 1084: .I rc ! 1085: exits with status 1.) ! 1086: .NH ! 1087: Advanced I/O Redirection ! 1088: .PP ! 1089: .I Rc ! 1090: allows redirection of file descriptors other than 0 and 1 ! 1091: (standard input and output) by specifying the file descriptor ! 1092: in square brackets ! 1093: .CW "[ ] ! 1094: after the ! 1095: .CW < ! 1096: or ! 1097: .CW > . ! 1098: For example, ! 1099: .P1 ! 1100: cc junk.c >[2]junk.diag ! 1101: .P2 ! 1102: saves the compiler's diagnostics in ! 1103: .CW junk.diag . ! 1104: .PP ! 1105: File descriptors may be replaced by a copy, in the sense of ! 1106: .I dup (2), ! 1107: of an already-open file by typing, for example ! 1108: .P1 ! 1109: cc junk.c >[2=1] ! 1110: .P2 ! 1111: This replaces file descriptor 2 with a copy of file descriptor 1. ! 1112: It is more useful in conjunction with other redirections, like this ! 1113: .P1 ! 1114: cc junk.c >junk.out >[2=1] ! 1115: .P2 ! 1116: Redirections are evaluated from left to right, so this redirects ! 1117: file descriptor 1 to ! 1118: .CW junk.out , ! 1119: then points file descriptor 2 at the same file. ! 1120: By contrast, ! 1121: .P1 ! 1122: cc junk.c >[2=1] >junk.out ! 1123: .P2 ! 1124: Redirects file descriptor 2 to a copy of file descriptor 1 ! 1125: (presumably the terminal), and then directs file descriptor 1 ! 1126: at a file. In the first case, standard and diagnostic output ! 1127: will be intermixed in ! 1128: .CW junk.out . ! 1129: In the second, diagnostic output will appear on the terminal, ! 1130: and standard output will be sent to the file. ! 1131: .PP ! 1132: File descriptors may be closed by using the duplication notation ! 1133: with an empty right-hand side. ! 1134: For example, ! 1135: .P1 ! 1136: cc junk.c >[2=] ! 1137: .P2 ! 1138: will discard diagnostics from the compilation. ! 1139: Often closing a file descriptor will not have the ! 1140: expected effect, because many UNIX programs do not ! 1141: behave politely when started with file descriptors ! 1142: 0, 1 or 2 closed. Consider, for example, ! 1143: .P1 ! 1144: who | tee a b c >[1=] ! 1145: .P2 ! 1146: One might expect this to produce copies of the output of ! 1147: .CW who ! 1148: on files ! 1149: .CW a , ! 1150: .CW b ! 1151: and ! 1152: .CW c , ! 1153: discarding the copy that ! 1154: .CW tee ! 1155: normally writes on its standard output. ! 1156: However, ! 1157: .CW tee ! 1158: does not check for its standard output being closed. ! 1159: When it opens ! 1160: .CW a , ! 1161: the file descriptor returned is 1, and unsurprisingly, ! 1162: .CW tee ! 1163: writes two interleaved copies of its input onto ! 1164: .CW a . ! 1165: It is better explicitly to direct the output at ! 1166: .CW /dev/null . ! 1167: .PP ! 1168: Arbitrary file descriptors may be sent through ! 1169: a pipe by typing, for example ! 1170: .P1 ! 1171: cc junk.c |[2] grep -v '^$' ! 1172: .P2 ! 1173: This deletes those ever-so-annoying blank lines ! 1174: from the C compiler's output. Note that the output ! 1175: of ! 1176: .CW grep ! 1177: still appears on file descriptor 1. ! 1178: .PP ! 1179: Very occasionally you may wish to connect the input side of ! 1180: a pipe to some file descriptor other than zero. ! 1181: The notation ! 1182: .P1 ! 1183: cmd1 |[5=19] cmd2 ! 1184: .P2 ! 1185: creates a pipeline with ! 1186: .CW cmd1 's ! 1187: file descriptor 5 connected through a pipe to ! 1188: .CW cmd2 's ! 1189: file descriptor 19. ! 1190: .NH ! 1191: Here documents ! 1192: .PP ! 1193: .I Rc ! 1194: procedures may include data, called ``here documents'', ! 1195: to be provided as input to commands, as in this version of the ! 1196: .I tel ! 1197: command ! 1198: .P1 ! 1199: for(i) grep $i <<! ! 1200: ... ! 1201: nls 2T-402 2912 ! 1202: norman 2C-514 2842 ! 1203: pjw 2T-502 7214 ! 1204: ... ! 1205: ! ! 1206: .P2 ! 1207: A here document is introduced by the redirection symbol ! 1208: .CW << , ! 1209: followed by an arbitrary eof marker ! 1210: .CW ! "" ( ! 1211: in the example). Lines following the command, ! 1212: up to a line containing only the eof marker are saved ! 1213: in a temporary file that it connected to the command's ! 1214: standard input when it is run. ! 1215: .PP ! 1216: .I Rc ! 1217: does variable substitution in here documents. The following ! 1218: .I subst ! 1219: command: ! 1220: .P1 ! 1221: ed $3 <<EOF ! 1222: g/$1/s//$2/g ! 1223: w ! 1224: EOF ! 1225: .P2 ! 1226: changes all occurrences of ! 1227: .CW $1 ! 1228: to ! 1229: .CW $2 ! 1230: in file ! 1231: .CW $3 . ! 1232: To include a literal ! 1233: .CW $ ! 1234: in a here document, type ! 1235: .CW $$ . ! 1236: If the name of a variable is followed immediately by ! 1237: .CW ^ , ! 1238: the caret is deleted. ! 1239: .PP ! 1240: Variable substitution can be entirely suppressed by enclosing ! 1241: the eof marker following ! 1242: .CW << ! 1243: in quotation marks. ! 1244: .PP ! 1245: Here documents may be provided on file descriptors other than 0 by typing, for example ! 1246: .P1 ! 1247: cmd <<[4]End ! 1248: ... ! 1249: End ! 1250: .P2 ! 1251: .NH ! 1252: Signals ! 1253: .PP ! 1254: .I Rc ! 1255: scripts normally terminate when an interrupt is received from the terminal. ! 1256: A function with the name of a signal, in lower case, is defined in the usual way, ! 1257: but called when ! 1258: .I rc ! 1259: receives the signal. Signals of interest are: ! 1260: .TP sighup ! 1261: Hangup. The controlling teletype has disconnected from ! 1262: .I rc . ! 1263: .TP sigint ! 1264: The interrupt character (usually ASCII del) was typed on the controlling terminal. ! 1265: .TP sigquit ! 1266: The quit character (usually ASCII fs, ctrl-\e) was typed on the controlling terminal. ! 1267: .TP sigterm ! 1268: This signal is normally sent by ! 1269: .I kill (1). ! 1270: .TP sigexit ! 1271: An artificial signal sent when ! 1272: .I rc ! 1273: is about to exit. ! 1274: .LP ! 1275: As an example, ! 1276: .P1 ! 1277: fn sigint{ ! 1278: rm /tmp/junk ! 1279: exit ! 1280: } ! 1281: .P2 ! 1282: sets a trap for the keyboard interrupt that ! 1283: removes a temporary file before exiting. ! 1284: .PP ! 1285: Signals will be ignored if the signal routine is set to ! 1286: .CW {} . ! 1287: Signals revert to their default behavior when their handlers' ! 1288: definitions are deleted. ! 1289: .NH ! 1290: Environment ! 1291: .PP ! 1292: The environment is a list of name-value pairs made available to ! 1293: executing binaries. On UNIX the environment is passed ! 1294: to commands as a second argument list containing ! 1295: an entry for each variable whose value is non-empty, and ! 1296: an entry for each function. UNIX does not directly support ! 1297: environment entries containing multiple strings, so if a variable ! 1298: has more than one component, these are separated by ctrl-a ! 1299: .CW \e001 ) ( ! 1300: characters. ! 1301: .PP ! 1302: On Plan 9, the environment is stored in a file system named ! 1303: .CW #e , ! 1304: normally mounted on ! 1305: .CW /env . ! 1306: The value of each variable is stored in a separate file, with components ! 1307: terminated by ASCII nuls. ! 1308: (This is not quite as horrendous as it sounds, the file system is ! 1309: maintained entirely in core, so no disk or network access is involved.) ! 1310: The contents of ! 1311: .CW /env ! 1312: are shared on a per-process group basis \(mi when a new process group is ! 1313: created it effectively attaches ! 1314: .CW /env ! 1315: to a new file system initialized with a copy of the old one. ! 1316: A consequence of this organization is that commands can change environment ! 1317: entries and see the changes reflected in ! 1318: .I rc . ! 1319: This is not possible on UNIX, as the environment is passed to children by ! 1320: .I exec (2), ! 1321: but is not passed back by ! 1322: .I fork (2) ! 1323: and ! 1324: .I wait (2). ! 1325: .PP ! 1326: There is not currently a way on Plan 9 to place functions in the environment, ! 1327: although this could easily done by mounting another instance of ! 1328: .CW #e ! 1329: on another directory. The problem is that currently there can be only one instance of ! 1330: .CW #e ! 1331: per process group. ! 1332: .NH ! 1333: Local Variables ! 1334: .PP ! 1335: It is often useful to set a variable for the duration ! 1336: of a single command. An assignment followed by a command ! 1337: has this effect. For example ! 1338: .P1 ! 1339: a=global ! 1340: a=local echo $a ! 1341: echo $a ! 1342: .P2 ! 1343: will print ! 1344: .P1 ! 1345: local ! 1346: global ! 1347: .P2 ! 1348: This works even for compound commands, like ! 1349: .P1 ! 1350: f=/fairly/long/file/name { ! 1351: { wc $f ! 1352: spell $f ! 1353: diff $f.old $f ! 1354: } | pr -h 'Facts about '$f | ! 1355: lp -ddp ! 1356: } ! 1357: .P2 ! 1358: .NH ! 1359: Invocation ! 1360: .PP ! 1361: When ! 1362: .I rc ! 1363: starts, it digests its option arguments, initializes variables ! 1364: and functions from the environment, sets ! 1365: .CW $* , ! 1366: .CW $pid ! 1367: and, if the ! 1368: .CW -c ! 1369: option is given, ! 1370: .CW $cflag , ! 1371: and starts reading commands. ! 1372: .PP ! 1373: Most of ! 1374: .I rc 's ! 1375: initialization is done in a command file that is run at startup. ! 1376: On UNIX the file is called ! 1377: .CW /usr/lib/rcmain . ! 1378: On Plan 9 it is ! 1379: .CW /sys/lib/rcmain . ! 1380: .LP ! 1381: Legal options are: ! 1382: .TP "-c \fIstring ! 1383: Commands are read from ! 1384: .I string . ! 1385: .TP -e ! 1386: Exit if ! 1387: .CW $status ! 1388: is non-zero after executing any simple command. ! 1389: .TP -i ! 1390: Interactive mode. ! 1391: Also set if ! 1392: .I rc ! 1393: is given no arguments and its standard input is a terminal, ! 1394: as determined by ! 1395: .I isatty (3) ! 1396: on UNIX, or by presumption on Plan 9. ! 1397: Commands are prompted for using ! 1398: .CW $prompt . ! 1399: .CW SIGINT ! 1400: and ! 1401: .CW SIGQUIT ! 1402: are caught and sloughed off. ! 1403: .TP -I ! 1404: Non-interactive mode. ! 1405: Suppresses interactive mode even if ! 1406: .I rc ! 1407: is given no arguments and its standard input is a terminal. ! 1408: .TP -l ! 1409: Login mode. ! 1410: Also set if the first character of argument zero is ! 1411: .CW - ! 1412: (this is an obscure UNIX convention). ! 1413: .I Rc ! 1414: reads commands from ! 1415: .CW $home/.rcrc , ! 1416: if it exists, before reading its normal input. ! 1417: .TP -p ! 1418: Protected mode. ! 1419: .CW $path ! 1420: is set to ! 1421: .CW "(/bin /usr/bin) ! 1422: on UNIX, or ! 1423: .CW "/bin ! 1424: on Plan 9, regardless of the setting in the environment. ! 1425: Furthermore, functions are not initialized from the environment. ! 1426: This provides a ``protected environment'' in which it is ! 1427: difficult for malicious users to subvert an ! 1428: .I rc ! 1429: script by placing Trojan-horse versions of commands in ! 1430: the environment or an unprotected directory. On Plan 9 this is ! 1431: not much use, since the meaning of all names, including those in ! 1432: .CW /bin , ! 1433: is determined by the user. ! 1434: .TP -v ! 1435: Echo input on file descriptor 2 (diagnostic output) as it is read. ! 1436: Useful for clarifying syntax problems in ! 1437: .I rc ! 1438: scripts. ! 1439: .TP -x ! 1440: Print each simple command on diagnostic output before executing it. ! 1441: Useful for debugging ! 1442: .I rc ! 1443: scripts. ! 1444: .PP ! 1445: The following flags are useful primarily for debugging ! 1446: .I rc . ! 1447: .TP -d ! 1448: Causes ! 1449: .I rc ! 1450: only to catch ! 1451: .CW SIGINT , ! 1452: so that ! 1453: .CW SIGQUIT ! 1454: will cause it to dump core. ! 1455: .TP -r ! 1456: .I Rc 's ! 1457: interpreter will print a running commentary on its state. ! 1458: This is useful only for debugging ! 1459: .I rc . ! 1460: .TP -V ! 1461: Echo input on diagnostic output as it is read, including ! 1462: .CW rcmain , ! 1463: which is normally suppressed when using ! 1464: .CW -v . ! 1465: .NH ! 1466: Examples \(em \fIcd, pwd\fP ! 1467: .PP ! 1468: Here is a pair of functions that provide ! 1469: enhanced versions of the standard ! 1470: .CW cd ! 1471: and ! 1472: .CW pwd ! 1473: commands. (Thanks to Rob Pike for these.) ! 1474: .P1 ! 1475: ps1='% ' # default prompt ! 1476: tab=' ' # a tab character ! 1477: fn pbd{ ! 1478: /bin/pwd|sed 's;.*/;;' ! 1479: } ! 1480: fn cd{ ! 1481: builtin cd $1 && ! 1482: switch($#*){ ! 1483: case 0 ! 1484: dir=$home ! 1485: prompt=($ps1 $tab) ! 1486: case * ! 1487: switch($1) ! 1488: case /* ! 1489: dir=$1 ! 1490: prompt=(`{pbd}^$ps1 $tab) ! 1491: case */* ..* ! 1492: dir=() ! 1493: prompt=(`{pbd}^$ps1 $tab) ! 1494: case * ! 1495: dir=() ! 1496: prompt=($1^$ps1 $tab) ! 1497: } ! 1498: } ! 1499: } ! 1500: fn pwd{ ! 1501: if(~ $#dir 0) ! 1502: dir=`{/bin/pwd} ! 1503: echo $dir ! 1504: } ! 1505: .P2 ! 1506: Function ! 1507: .CW pwd ! 1508: is a version of the standard ! 1509: .CW pwd ! 1510: that caches its value in variable ! 1511: .CW $dir , ! 1512: because the genuine ! 1513: .CW pwd ! 1514: can be quite slow to execute. ! 1515: .PP ! 1516: Function ! 1517: .CW pbd ! 1518: is a helper that prints the last component of a directory name. ! 1519: Function ! 1520: .CW cd ! 1521: calls the ! 1522: .CW cd ! 1523: built-in, and checks that it was successful. ! 1524: If so, it sets ! 1525: .CW $dir ! 1526: and ! 1527: .CW $prompt . ! 1528: The prompt will include the last component of the ! 1529: current directory (except in the home directory, ! 1530: where it will be null), and ! 1531: .CW $dir ! 1532: will be reset either to the correct value or to ! 1533: .CW () , ! 1534: so that the ! 1535: .CW pwd ! 1536: function will work correctly. ! 1537: .NH ! 1538: Examples \(em \fIman\fP ! 1539: .PP ! 1540: The ! 1541: .I man ! 1542: command prints pages from of the UNIX Programmer's Manual. ! 1543: It is called, for example, as ! 1544: .P1 ! 1545: man 3 isatty ! 1546: man rc ! 1547: man -t cat ! 1548: .P2 ! 1549: In the first case, the page for ! 1550: .I isatty ! 1551: in section 3 is printed. ! 1552: In the second case, the manual page for ! 1553: .I rc ! 1554: is printed. Since no manual section is specified, ! 1555: all sections are searched for the page, and it is found ! 1556: in section 1. ! 1557: In the third case, the page for ! 1558: .I cat ! 1559: is typeset (the ! 1560: .CW -t ! 1561: option). ! 1562: .P1 ! 1563: cd /n/bowell/usr/man || { ! 1564: echo $0: Manual not on line! >[1=2] ! 1565: exit 1 ! 1566: } ! 1567: NT=n # default nroff ! 1568: s='*' # section, default try all ! 1569: for(i) switch($i){ ! 1570: case -t ! 1571: NT=t ! 1572: case -n ! 1573: NT=n ! 1574: case -* ! 1575: echo Usage: $0\e ! 1576: '[-nt] [section] page ...' >[1=2] ! 1577: exit 1 ! 1578: case [1-9] 10 ! 1579: s=$i ! 1580: case * ! 1581: eval 'pages=man'$s/$i'.*' ! 1582: for(page in $pages){ ! 1583: if(test -f $page) ! 1584: $NT^roff -man $page ! 1585: if not ! 1586: echo $0: $i not found >[1=2] ! 1587: } ! 1588: } ! 1589: .P2 ! 1590: Note the use of ! 1591: .CW eval ! 1592: to make a list of candidate manual pages. ! 1593: Without ! 1594: .CW eval , ! 1595: the ! 1596: .CW * ! 1597: stored in ! 1598: .CW $s ! 1599: would not trigger filename matching ! 1600: \(em it's enclosed in quotation marks, ! 1601: and even if it weren't, it would be expanded ! 1602: when assigned to ! 1603: .CW $s . ! 1604: Eval causes its arguments ! 1605: to be re-processed by ! 1606: .I rc 's ! 1607: parser and interpreter, effectively delaying ! 1608: evaluation of the ! 1609: .CW * ! 1610: until the assignment to ! 1611: .CW $pages . ! 1612: .NH ! 1613: Examples \(em \fIholmdel\fP ! 1614: .PP ! 1615: The following ! 1616: .I rc ! 1617: script plays the deceptively simple game ! 1618: .I holmdel , ! 1619: in which the players alternately name Bell Labs locations, ! 1620: the winner being the first to mention Holmdel. ! 1621: .KF ! 1622: .P1 ! 1623: t=/tmp/holmdel$pid ! 1624: fn read{ ! 1625: $1=`{awk '{print;exit}'} ! 1626: } ! 1627: ifs=' ! 1628: \&' # just a newline ! 1629: fn sigexit sigint sigquit sighup{ ! 1630: rm -f $t ! 1631: exit ! 1632: } ! 1633: cat <<'!' >$t ! 1634: Allentown ! 1635: Atlanta ! 1636: Cedar Crest ! 1637: Chester ! 1638: Columbus ! 1639: Elmhurst ! 1640: Fullerton ! 1641: Holmdel ! 1642: Indian Hill ! 1643: Merrimack Valley ! 1644: Morristown ! 1645: Piscataway ! 1646: Reading ! 1647: Short Hills ! 1648: South Plainfield ! 1649: Summit ! 1650: Whippany ! 1651: West Long Branch ! 1652: ! ! 1653: while(true){ ! 1654: lab=`{/usr/games/fortune $t} ! 1655: echo $lab ! 1656: if(~ $lab Holmdel){ ! 1657: echo You lose. ! 1658: exit ! 1659: } ! 1660: while(read lab ! 1661: ! grep -i -s $lab $t) ! 1662: echo No such location. ! 1663: if(~ $lab [hH]olmdel){ ! 1664: echo You win. ! 1665: exit ! 1666: } ! 1667: } ! 1668: .P2 ! 1669: .KE ! 1670: .LP ! 1671: This script is worth describing in detail ! 1672: (rather, it would be if it weren't so silly.) ! 1673: .PP ! 1674: Variable ! 1675: .CW $t ! 1676: is an abbreviation for the name of a temporary file. ! 1677: Including ! 1678: .CW $pid ! 1679: in the names of temporary files insures that their ! 1680: names won't collide, in case more than one instance ! 1681: of the script is running at a time. ! 1682: .PP ! 1683: Function ! 1684: .CW read 's ! 1685: argument is the name of a variable into which a ! 1686: line gathered from standard input is read. ! 1687: .CW $ifs ! 1688: is set to just a newline. Thus ! 1689: .CW read 's ! 1690: input is not split apart at spaces, but the terminating ! 1691: newline is deleted. ! 1692: .PP ! 1693: A handler is set to catch ! 1694: .CW sigint , ! 1695: .CW sigquit , ! 1696: and ! 1697: .CW sighup, ! 1698: and the artificial ! 1699: .CW sigexit ! 1700: signal. It just removes the temporary file and exits. ! 1701: .PP ! 1702: The temporary file is initialized from a here ! 1703: document containing a list of Bell Labs locations, and ! 1704: the main loop starts. ! 1705: .PP ! 1706: First, the program guesses a location (in ! 1707: .CW $lab ) ! 1708: using the ! 1709: .CW fortune ! 1710: program to pick a random line from the location list. ! 1711: It prints the location, and if it guessed Holmdel, prints ! 1712: a message and exits. ! 1713: .PP ! 1714: Then it uses the ! 1715: .CW read ! 1716: function to get lines from standard input and validity-check ! 1717: them until it gets a legal name. ! 1718: Note that the condition part of a ! 1719: .CW while ! 1720: can be a compound command. Only the exit status of the ! 1721: last command in the sequence is checked. ! 1722: .PP ! 1723: Again, if the result ! 1724: is Holmdel, it prints a message and exits. ! 1725: Otherwise it goes back to the top of the loop. ! 1726: .NH ! 1727: Discussion ! 1728: .PP ! 1729: Steve Bourne's ! 1730: .CW /bin/sh ! 1731: is extremely well-designed; any successor is bound to ! 1732: suffer in comparison. I have tried to fix its ! 1733: best-acknowledged shortcomings and to simplify things ! 1734: wherever possible, usually by omitting unessential features. ! 1735: Only when irresistibly tempted have I introduced novel ideas. ! 1736: Obviously I have tinkered extensively with Bourne's syntax, ! 1737: that being where his work was most open to criticism. ! 1738: .PP ! 1739: The most important principle in ! 1740: .I rc 's ! 1741: design is that it's not a macro processor. Input is never ! 1742: scanned more than once by the lexical and syntactic analysis ! 1743: code (except, of course, by the ! 1744: .CW eval ! 1745: command, whose ! 1746: .I "raison d'etre ! 1747: is to break the rule). ! 1748: .PP ! 1749: Bourne shell scripts can often be made ! 1750: to run wild by passing them arguments containing spaces. ! 1751: These will be split into multiple arguments using ! 1752: .CW IFS , ! 1753: often as inopportune times. ! 1754: In ! 1755: .I rc , ! 1756: values of variables, including command line arguments, are not re-read ! 1757: when substituted into a command. ! 1758: Arguments have presumably been scanned in the parent process, and ought ! 1759: not to be re-read. ! 1760: .PP ! 1761: Why does Bourne re-scan commands after variable substitution? ! 1762: He needs to be able to store lists of arguments in variables whose values are ! 1763: character strings. ! 1764: If we eliminate re-scanning, we must change the type of variables, so that ! 1765: they can explicitly carry lists of strings. ! 1766: .PP ! 1767: This introduces some ! 1768: conceptual complications. We need a notation for lists of words. ! 1769: There are two different kinds of concatenation, for strings \(em ! 1770: .CW $a^$b , ! 1771: and lists \(em ! 1772: .CW "($a $b)" . ! 1773: The difference between ! 1774: .CW () ! 1775: and ! 1776: .CW '' ! 1777: is confusing to novices, ! 1778: although the distinction is arguably sensible \(em ! 1779: a null argument is not the same as no argument. ! 1780: .PP ! 1781: Bourne also rescans input when doing command substitution. ! 1782: This is because the text enclosed in back-quotes is not ! 1783: properly a string, but a command. Properly, it ought to ! 1784: be parsed when the enclosing command is, but this makes ! 1785: it difficult to ! 1786: handle nested command substitutions, like this: ! 1787: .P1 ! 1788: size=`wc -l \e`ls -t|sed 1q\e`` ! 1789: .P2 ! 1790: The inner back-quotes must be escaped ! 1791: to avoid terminating the outer command. ! 1792: This can get much worse than the above example; ! 1793: the number of ! 1794: .CW \e 's ! 1795: required is exponential in the nesting depth. ! 1796: .I Rc ! 1797: fixes this by making the backquote a unary operator ! 1798: whose argument is a command, like this: ! 1799: .P1 ! 1800: size=`{wc -l `{ls -t|sed 1q}} ! 1801: .P2 ! 1802: No escapes are ever required, and the whole thing ! 1803: is parsed in one pass. ! 1804: .PP ! 1805: A similar rationale explains why ! 1806: .I rc ! 1807: defines signal handlers as though they were functions, ! 1808: instead of associating a string with each signal, as Bourne does, ! 1809: with the attendant possibility of getting a syntax error message ! 1810: in response to typing the interrupt character. Since ! 1811: .I rc ! 1812: parses input when typed, it reports errors when you make them. ! 1813: .PP ! 1814: For all this trouble, we gain substantial semantic simplifications. ! 1815: There is no need for the distinction between ! 1816: .CW $* ! 1817: and ! 1818: .CW $@ . ! 1819: There is no need for four types of quotation, nor the ! 1820: extremely complicated rules that govern them. In ! 1821: .I rc ! 1822: you use quotation marks exactly when you want a syntax character ! 1823: to appear in an argument. ! 1824: .CW IFS ! 1825: is no longer used, except in the one case where it was indispensable: ! 1826: converting command output into argument lists during command substitution. ! 1827: .PP ! 1828: This also avoids an important security hole|reference(reeds loophole). ! 1829: .I System (3) ! 1830: and ! 1831: .I popen (3) ! 1832: call ! 1833: .CW /bin/sh ! 1834: to execute a command. It is impossible to use either ! 1835: of these routines with any assurance that the specified command will ! 1836: be executed, even if the caller of ! 1837: .I system ! 1838: or ! 1839: .I popen ! 1840: specifies a full path name for the command. This can be devastating ! 1841: if it occurs in a set-userid program. ! 1842: The problem is that ! 1843: .CW IFS ! 1844: is used to split the command into words, so an attacker can just ! 1845: set ! 1846: .CW IFS=/ ! 1847: in his environment and leave a Trojan horse ! 1848: named ! 1849: .CW usr ! 1850: or ! 1851: .CW bin ! 1852: in the current working directory before running the privileged program. ! 1853: .I Rc ! 1854: fixes this by not ever rescanning input for any reason. ! 1855: .PP ! 1856: Most of the other differences between ! 1857: .I rc ! 1858: and the Bourne shell are not so serious. I eliminated Bourne's ! 1859: peculiar forms of variable substitution, like ! 1860: .P1 ! 1861: echo ${a=b} ${c-d} ${e?error} ! 1862: .P2 ! 1863: because they are little used, redundant and easily ! 1864: expressed in less abstruse terms. ! 1865: I deleted the builtins ! 1866: .CW export , ! 1867: .CW readonly , ! 1868: .CW break , ! 1869: .CW continue , ! 1870: .CW read , ! 1871: .CW return , ! 1872: .CW set , ! 1873: .CW times ! 1874: and ! 1875: .CW unset ! 1876: because they seem redundant or ! 1877: only marginally useful. ! 1878: .PP ! 1879: Where Bourne's syntax draws from Algol 68, ! 1880: .I rc 's ! 1881: is based on C or Awk. This is harder to defend. ! 1882: I believe that, for example ! 1883: .P1 ! 1884: if(test -f junk) rm junk ! 1885: .P2 ! 1886: is better syntax than ! 1887: .P1 ! 1888: if test -f junk; then rm junk; fi ! 1889: .P2 ! 1890: because it is less cluttered with keywords, ! 1891: it avoids the semicolons that Bourne requires ! 1892: in odd places, ! 1893: and the syntax characters better set off the ! 1894: active parts of the command. ! 1895: .PP ! 1896: The one bit of large-scale syntax that Bourne ! 1897: unquestionably does better than ! 1898: .I rc ! 1899: is the ! 1900: .CW if ! 1901: statement with ! 1902: .CW "else ! 1903: clause. ! 1904: .I Rc 's ! 1905: .CW if ! 1906: has no terminating ! 1907: .CW fi -like ! 1908: bracket. As a result, the parser cannot ! 1909: tell whether or not to expect an ! 1910: .CW "else ! 1911: clause without looking ahead in its input. ! 1912: The problem is that after reading, for example ! 1913: .P1 ! 1914: if(test -f junk) echo junk found ! 1915: .P2 ! 1916: in interactive mode, ! 1917: .I rc ! 1918: cannot decide whether to execute it immediately and print ! 1919: .CW $prompt(1) , ! 1920: or to print ! 1921: .CW $prompt(2) ! 1922: and wait for the ! 1923: .CW "else ! 1924: to be typed. ! 1925: In the Bourne shell, this is not a problem, because the ! 1926: .CW if ! 1927: command must end with ! 1928: .CW fi , ! 1929: regardless of whether it contains an ! 1930: .CW else ! 1931: or not. ! 1932: .PP ! 1933: .I Rc 's ! 1934: admittedly feeble solution is to declare that the ! 1935: .CW else ! 1936: clause is a separate statement, with the semantic ! 1937: proviso that it must immediately follow an ! 1938: .CW if , ! 1939: and to call it ! 1940: .CW "if not ! 1941: rather than ! 1942: .CW else , ! 1943: as a reminder that something odd is going on. ! 1944: The only noticeable consequences of this is that ! 1945: the braces are required in the construction ! 1946: .P1 ! 1947: for(i){ ! 1948: if(test -f $i) echo $i found ! 1949: if not echo $i not found ! 1950: } ! 1951: .P2 ! 1952: and that ! 1953: .I rc ! 1954: resolves the ``dangling else'' ambiguity in opposition ! 1955: to most people's expectations. ! 1956: .PP ! 1957: It is remarkable that in the four most recent editions of the UNIX ! 1958: programmer's manual the Bourne shell grammar described in the manual page ! 1959: does not admit the command ! 1960: .CW who|wc . ! 1961: This is surely an oversight, but it suggests something darker: ! 1962: nobody really knows what the Bourne shell's grammar is. Even examination ! 1963: of the source code is little help. The parser is implemented by recursive ! 1964: descent, but the routines corresponding to the syntactic categories all ! 1965: have a flag argument that subtly changes their operation depending on the ! 1966: context. ! 1967: .I Rc 's ! 1968: parser is implemented using ! 1969: .I yacc , ! 1970: so I can say precisely what the grammar is \(em it's reproduced in the appendix. ! 1971: .PP ! 1972: Its lexical structure is harder to describe. ! 1973: I would simplify it considerably ! 1974: except for two things. ! 1975: There is a lexical kludge to distinguish between parentheses that immediately ! 1976: follow a word with no intervening spaces and those that don't that I would ! 1977: eliminate if there were a reasonable pair of characters to use ! 1978: for subscript brackets. I could also eliminate the insertion of ! 1979: free carets if users were not adamant about it. ! 1980: .NH ! 1981: Acknowledgements ! 1982: .PP ! 1983: Rob Pike, Howard Trickey and other Plan 9 users have been insistent, incessant ! 1984: sources of good ideas and criticism. Some examples in this document are plagiarized ! 1985: from |reference(bstj shell), as are most of ! 1986: .I rc 's ! 1987: good features. ! 1988: .NH ! 1989: References ! 1990: .LP ! 1991: |reference_placement ! 1992: .SH ! 1993: Appendix \(em an ! 1994: .I rc ! 1995: grammar ! 1996: .PP ! 1997: Below is reproduced ! 1998: .I rc 's ! 1999: .I yacc ! 2000: grammar, extracted directly from the source code, edited only ! 2001: to remove semantic actions. The grammar describes a single ! 2002: command. An ! 2003: .I rc ! 2004: script is a sequence of zero or more of these. ! 2005: .PP ! 2006: In the grammar, the token ! 2007: .CW WORD ! 2008: represents either a quoted string or ! 2009: a non-empty string of characters other ! 2010: than blank, tab, newline or any of the following: ! 2011: .P1 ! 2012: # ; & | ^ $ = ` ' { } ( ) < > ! 2013: .P2 ! 2014: with the proviso that a word that immediately follows a ! 2015: .CW $ ! 2016: or ! 2017: .CW $# ! 2018: ends at the first character that is not alphanumeric or ! 2019: .CW _ ! 2020: or ! 2021: .CW * . ! 2022: .PP ! 2023: The token ! 2024: .CW SUB ! 2025: represents a left parenthesis that follows a ! 2026: .CW WORD ! 2027: with no intervening spaces and therefore should be interpreted ! 2028: as the start of a subscript. ! 2029: .CW REDIR ! 2030: represents any of the redirection symbols, ! 2031: .P1 ! 2032: > >[\fIn\fT] ! 2033: < <[\fIn\fT] ! 2034: >> >>[\fIn\fT] ! 2035: << <<[\fIn\fT] ! 2036: .P2 ! 2037: .CW PIPE ! 2038: is any of the pipe symbols ! 2039: .P1 ! 2040: | |[\fIn\fT] |[\fIn\fT=\fIm\fT] ! 2041: .P2 ! 2042: .CW DUP ! 2043: is any of the file-descriptor duplication or closing symbols ! 2044: .P1 ! 2045: >[\fIn\fT=\fIm\fT] <[\fIn\fT=\fIm\fT] >>[\fIn\fT=\fIm\fT] ! 2046: >[\fIn\fT=] <[\fIn\fT=] >>[\fIn\fT=] ! 2047: .P2 ! 2048: .CW ANDAND ! 2049: stands for ! 2050: .CW && , ! 2051: .CW OROR ! 2052: stands for ! 2053: .CW || , ! 2054: and ! 2055: .CW COUNT ! 2056: stands for ! 2057: .CW $# . ! 2058: The other token names stand for or key words, which are lexically ! 2059: indistinguishable from ! 2060: .CW WORD s: ! 2061: .P1 ! 2062: BANG ! ! 2063: FN fn ! 2064: FOR for ! 2065: IF if ! 2066: IN in ! 2067: NOT not ! 2068: SUBSHELL @ ! 2069: SWITCH switch ! 2070: TWIDDLE ~ ! 2071: WHILE while ! 2072: .P2 ! 2073: .PP ! 2074: Comments start with ! 2075: .CW # ! 2076: and continue to the end of the line, and are deleted by lexical ! 2077: analysis, which also converts a backslash ! 2078: .CW \e ) ( ! 2079: followed by a newline into a space, and ! 2080: inserts free carets whenever a ! 2081: .CW WORD ! 2082: is followed by another ! 2083: .CW WORD ! 2084: or a ! 2085: .CW ` ! 2086: or ! 2087: .CW $ , ! 2088: with no intervening spaces. ! 2089: .PP ! 2090: Here then is ! 2091: .I rc 's ! 2092: grammar. Semantic actions that call function ! 2093: .CW skipnl ! 2094: have been included at places where a command ! 2095: may be continued on a new line. ! 2096: .br ! 2097: \X'PARM CT 80' ! 2098: .KS ! 2099: .P1 ! 2100: %term FOR IN WHILE IF NOT ! 2101: %term TWIDDLE BANG SUBSHELL ! 2102: %term SWITCH FN WORD REDIR DUP ! 2103: %term PIPE SUB ! 2104: %left IF WHILE FOR SWITCH ')' NOT ! 2105: %left ANDAND OROR ! 2106: %left BANG SUBSHELL ! 2107: %left PIPE ! 2108: %left '^' ! 2109: %right '$' COUNT ! 2110: %left SUB ! 2111: %% ! 2112: rc: ! 2113: | line '\en' ! 2114: line: cmd ! 2115: | cmdsa line ! 2116: body: cmd ! 2117: | cmdsan body ! 2118: cmdsa: cmd ';' ! 2119: | cmd '&' ! 2120: cmdsan: cmdsa ! 2121: | cmd '\en' ! 2122: brace: '{' body '}' ! 2123: paren: '(' body ')' ! 2124: assign: first '=' word ! 2125: epilog: ! 2126: | redir epilog ! 2127: redir: REDIR word ! 2128: | DUP ! 2129: cmd: ! 2130: | brace epilog ! 2131: | IF paren {skipnl();} cmd ! 2132: | IF NOT {skipnl();} cmd ! 2133: | FOR '(' word IN words ')' ! 2134: {skipnl();} cmd ! 2135: | FOR '(' word ')' ! 2136: {skipnl();} cmd ! 2137: | WHILE paren {skipnl();} cmd ! 2138: | SWITCH word {skipnl();} brace ! 2139: | simple ! 2140: | TWIDDLE word words ! 2141: | cmd ANDAND cmd ! 2142: | cmd OROR cmd ! 2143: | cmd PIPE cmd ! 2144: | redir cmd %prec BANG ! 2145: | assign cmd %prec BANG ! 2146: | BANG cmd ! 2147: | SUBSHELL cmd ! 2148: | FN words brace ! 2149: | FN words ! 2150: .P2 ! 2151: .KE ! 2152: .KS ! 2153: .P1 ! 2154: simple: first ! 2155: | simple word ! 2156: | simple redir ! 2157: first: comword ! 2158: | first '^' word ! 2159: word: keyword ! 2160: | comword ! 2161: | word '^' word ! 2162: comword: '$' word ! 2163: | '$' word SUB words ')' ! 2164: | COUNT word ! 2165: | WORD ! 2166: | '`' brace ! 2167: | '(' words ')' ! 2168: | REDIR brace ! 2169: keyword: FOR|IN|WHILE|IF|NOT ! 2170: | TWIDDLE|BANG|SUBSHELL|SWITCH ! 2171: | FN ! 2172: words: ! 2173: | words word ! 2174: .P2 ! 2175: .KE
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.