Annotation of 43BSDTahoe/new/help/src/cshell/internals, revision 1.1

1.1     ! root        1: .TI CSHELL/INTERNALS
        !             2: Internal Operation of the C Shell
        !             3: 
        !             4: 
        !             5: The whole point of the shell is to find programs and start them running.
        !             6: When you enter a command it searches for a program to do your bidding,
        !             7: starts it running, stands by idly until it completes, and then prints
        !             8: a prompt for another command.
        !             9: It continues this read-execute-prompt cycle indefinitely, stopping
        !            10: only when you logout or the computer goes down.
        !            11: 
        !            12: Ultimately the shell's purpose is to take a user command and put it
        !            13: in the form Unix requires for starting execution of new
        !            14: programs:  execl( PROGFILE, ARG0, ARG1, ARG2, ..., 0 ).
        !            15: For example, if your command were "nroff -ms myfile", the shell's job
        !            16: would be to execl( "/usr/bin/nroff", "nroff", "-ms", "myfile", 0 ),
        !            17: where "/usr/bin/nroff" tells Unix in which file to find the nroff program.
        !            18: In this case the shell had very little work to do.
        !            19: If your next command were "!! | lpr ; wc * > ~/wcout",
        !            20: the shell would have much more work to do and end up with 3 execl calls
        !            21: bearing little resemblance to your command.
        !            22: This is important because what the shell winds up sending to execl
        !            23: as arguments are what the programs involved really see.
        !            24: 
        !            25: A program that is executing, as opposed
        !            26: to one that is stored in a file, is called a process.
        !            27: When you login, Unix finds the C shell program in the file "/bin/csh"
        !            28: and starts it running as a process on your terminal.
        !            29: The same happens to everyone else when they login,
        !            30: but each of the resulting processes is independent and has
        !            31: no knowledge of any other processes except those it might create.
        !            32: Thus you have your own shell when you login, and can
        !            33: in fact personalize it to some extent.
        !            34: 
        !            35: In a little greater detail than before,
        !            36: here is what the C shell does with a command.
        !            37: To illustrate this suppose you enter the command
        !            38: .br
        !            39:        % nroff -ms chap* > outfile
        !            40: .br
        !            41: Your shell process ...
        !            42: 
        !            43: [1] reads the command and breaks it into separate
        !            44: command words:  "nroff", "-ms", "chap*" ">", "outfile";
        !            45: 
        !            46: [2] makes new command words if necessary:  in this case replaces the
        !            47: command word "chap*" by all filenames beginning with "chap",
        !            48: for example, "chapintro", "chapter1", "chapter2";
        !            49: 
        !            50: [3] finds a file (assumed to contain the program)
        !            51: named by the first command word:  "/usr/bin/nroff";
        !            52: 
        !            53: [4] makes a copy of itself -- a child process -- which will later be
        !            54: transformed into the nroff process.
        !            55: 
        !            56: Here the child and parent processes do different things.
        !            57: 
        !            58: [5] The child sets up input and output, removing command words which
        !            59: indicate redirection:  in this case opens a file
        !            60: called "output" to which all future output from this child
        !            61: process will be written instead of the terminal and removes
        !            62: the words ">" and "outfile" from your command;
        !            63: 
        !            64: [6] the child transforms itself into the program found in step 3 above
        !            65: using execl:  execl( "/usr/bin/nroff", "nroff", "-ms", "chapintro",
        !            66: "chapter1", "chapter2", 0 );
        !            67: 
        !            68: [7] the child dies, either because it is done or there was an error,
        !            69: at which point the Unix kernel removes all
        !            70: traces of it and sends a signal of this event to the parent process;
        !            71: 
        !            72: [8] the parent process meanwhile literally waits idly for the child
        !            73: process to finish, and then issues a prompt for another command.
        !            74: 
        !            75: Each of these steps have interesting and important ramifications.
        !            76: Some are explained below, others are mentioned below and explained
        !            77: elsewhere.
        !            78: 
        !            79: [1] Reads the command and breaks it into separate command words.
        !            80: 
        !            81: This step (lexical analysis) is needed to get the command words
        !            82: (arguments) into the execl format.
        !            83: It gives the typist some flexibility while imposing some restrictions.
        !            84: In particular, the shell breaks the line into separate words
        !            85: at blanks and tabs, treating multiple blanks and tabs as if they
        !            86: were one blank.
        !            87: So, for example, if you accidentally type extra blanks at
        !            88: the beginning or end of the command, or between words, the
        !            89: shell will probably do what you had in mind.
        !            90: On the other hand, if you leave out blanks between two adjacent
        !            91: arguments, it will go ahead and bundle them up as one word.
        !            92: For example, the shell considers the command
        !            93: .br
        !            94:        % nroff-ms                myfile
        !            95: .br
        !            96: as having only two words, the name of the command being "nroff-ms",
        !            97: then tries unsuccessfully to locate the program (step 3)
        !            98: in a file of that name and responds with
        !            99: .br
        !           100:        nroff-ms: Command not found.
        !           101: .br
        !           102: The last argument would have been correctly interpreted as "myfile".
        !           103: To add another twist, the command
        !           104: .br
        !           105:        nroff -ms-o1,5 myfile
        !           106: .br
        !           107: would be execl'd successfully (step 6) but would provoke
        !           108: an error message from nroff.
        !           109: 
        !           110: One additional rule says that any one of the
        !           111: characters &|;<>() is considered a separate word,
        !           112: except when one of &|<> appear doubled, in which case
        !           113: the doubled character is one word.
        !           114: For example, the commands
        !           115: .br
        !           116:        % neqn    <paper|nroff -ms>>   outfile&
        !           117: .br
        !           118:        % neqn < paper | nroff -ms >> outfile &
        !           119: .br
        !           120: are interpreted identically, each consisting of 9 words.
        !           121: 
        !           122: On the other hand, if you want a blank, tab, or one of &|;<>()
        !           123: to be considered part of another word, you must surround
        !           124: it with quote marks of the type ", `, or ', or precede it with a \\
        !           125: (use of \\ is also termed quoting).
        !           126: If you want a carriage-return (newline) to be part of a word,
        !           127: you must surround it with quote marks AND precede it with a \\,
        !           128: since preceding it with a \\ and
        !           129: not using quote marks is treated as a blank.
        !           130: 
        !           131: Beware.
        !           132: Strictly speaking, quoting prevents the shell from interpreting
        !           133: the quoted characters according to its usual practice, and this discussion
        !           134: only mentions how the usual practice is suspended with respect
        !           135: to word separation.
        !           136: There are other much more profound side-effects of quoting depending on both
        !           137: the quoted and the quoting characters.
        !           138: The documentation is perhaps more unyielding, incomplete, and confusing
        !           139: on this issue than on any other.
        !           140: 
        !           141: [2] Makes new command words if necessary.
        !           142: 
        !           143: The C Shell recognizes a large variety of characters and constructs
        !           144: as having special meanings and substitutes other words in their place.
        !           145: This means that if your command line contains any of them,
        !           146: as in "!! | lpr ; wc * > ~/wcout" from before,
        !           147: the resulting call (or calls) to execl (step 6) may be the result
        !           148: of sweeping changes made in this step.
        !           149: Note that the programs being called never see your original command
        !           150: and never have to know anything about the special characters.
        !           151: Consequently, the same substitution rules apply to ALL programs called
        !           152: from the shell (for example, "lpr", "vi", "nroff", etc.).
        !           153: 
        !           154: Substitutions are classified by type and are applied in a definite order.
        !           155: The shell scans command words for characters or constructs of the first type,
        !           156: making substitutions if it finds any.
        !           157: Then it takes the resulting command words and scans them to find and make
        !           158: substitutions of the second type, if any, and so forth.
        !           159: Here is a list of substitution types in order with an indication of the kinds
        !           160: of special characters that will trigger them.
        !           161: 
        !           162: .nf
        !           163: .ta 8n 16n 24n 32n 40n 48n 56n 64n
        !           164: Type           Triggered By            Typical Uses
        !           165: -------------------------------------------------------------------
        !           166: History                !event, ^old^new        re-use earlier commands
        !           167: Alias          first command word      re-name commands
        !           168: Variable       $var, $#var, $var[n]    scripts, personalized shell
        !           169: Command                `shell command`         use command output as args
        !           170: Filename       *, ?, [], {}, ~         abbreviate groups of files
        !           171: Input/Output   <, >, |, <<, >>, $<     re-route input and output
        !           172: Expressions    ( x <>=!~+-*/()&|^ y )  arithmetic and branching
        !           173: .fi
        !           174: 
        !           175: In the hands of a sober, well-informed user, substitutions are very
        !           176: useful:  (1) they can save tremendous amounts of typing, (2) they
        !           177: need only be learned for the shell, since all programs called by
        !           178: users have to go through the shell, and (3) they make it possible
        !           179: to write programs consisting of shell commands.
        !           180: 
        !           181: In the wrong hands, however, substitutions can be a tricky.
        !           182: To help you practice, the shell provides a way for you to see
        !           183: exactly what it comes up with just before it calls execl.
        !           184: The command "set echo" will cause it to print your command after
        !           185: all substitutions have been made, just before calling execl.
        !           186: To avoid the danger of executing a possibly incorrect command, you
        !           187: can test whether a construct will end up the way you think
        !           188: just by entering it as an argument to the "echo" command.
        !           189: The "echo" command does nothing more than print its arguments
        !           190: on the terminal and like all commands is subject to substitutions.
        !           191: So, for example, "echo *" prints the words that would result,
        !           192: on any command line, from substituting for * (which lists all your files).
        !           193: 
        !           194: [3] Finds a file named by the first command word.
        !           195: 
        !           196: The whole point of the shell is to run programs other than itself,
        !           197: such as "vi", "cc", "troff", etc.
        !           198: Occasionally there is a need for a command that the shell can perform
        !           199: internally, that is, without locating a program file or
        !           200: creating another process.
        !           201: So in this step the shell usually tries to locate a file containing the
        !           202: program named by the first command word, but not before checking
        !           203: to see if it belongs to the set of commands built-in to itself.
        !           204: 
        !           205: If a command is non-built-in, the shell scans a list of directories
        !           206: called the searchpath, which may be personalized for each user.
        !           207: It appends the first command word to the first directory on
        !           208: the list and checks to see if the resulting file name exists.
        !           209: If not, it checks the second directory in a similar fashion,
        !           210: and so forth, until a file is found, and that file name is
        !           211: used when execl is called in step 6.
        !           212: In the case that no file is found, the shell reports this
        !           213: and prompts for another command.
        !           214: 
        !           215: If your searchpath becomes garbled, usually because you were
        !           216: experimenting with it, the shell may not find some or all of
        !           217: the usual non-built-in commands.
        !           218: Besides panicking, there are two things to do.
        !           219: Fortunately, the command to correct the searchpath is built-in
        !           220: and can still be used, but only if you recognize that
        !           221: that is the problem.
        !           222: Also, if the first command word begins with a /, the shell
        !           223: considers it to be the name of the program file to execute,
        !           224: for example, the command "/usr/ucb/vi .cshrc" would work.
        !           225: 
        !           226: If a command is built-in, the shell bypasses steps 4, 6, 7, and 8,
        !           227: which reduces run time greatly, and performs the command in its own way.
        !           228: For the sake of efficiency, a built-in command is preferred to a
        !           229: non-built-in command if they perform the same function, and that is
        !           230: why some of the built-in commands were created.
        !           231: Other commands were built-in because they would not have worked
        !           232: otherwise, due to the way that processes
        !           233: disappear completely in step 7; in particular, if a command is
        !           234: needed to change the behavior of your shell from that point on,
        !           235: a non-built-in command would only be able to change the characteristics
        !           236: of a child process of your shell, the shell process that will read
        !           237: your next command when the child dies leaving no trace of the change.
        !           238: 
        !           239: The "echo" command, for example, is built-in to the C shell
        !           240: because it is used so often.
        !           241: A quick and ugly way to list the files in your directory,
        !           242: without using the "ls" command, is to type "echo *".
        !           243: A very quick way to create a one line file, without "vi",
        !           244: is "echo This is a one line file. > oneliner".
        !           245: Some commands that have to be built-in are "cd", "set",
        !           246: "alias", and "history".
        !           247: Unfortunately, most built-in commands do not have separate manual
        !           248: sections, so the command "man set" will yield nothing, while "man csh"
        !           249: will tell you about "cd" after printing the first 9 pages or so.
        !           250: Ironically, "man echo" will display a manual page because users
        !           251: of the Bourne shell do not have a built-in "echo" command.
        !           252: 
        !           253: [4] Makes a copy of itself -- a child process.
        !           254: 
        !           255: The Unix kernel requires the C shell -- in fact, requires
        !           256: all programs that run other programs -- to use execl.
        !           257: Unfortunately, that causes the process running the new program
        !           258: to die when it is done.
        !           259: Your shell therefore has to create a new process to do the execl
        !           260: in order that the old process survive to prompt you for the
        !           261: next command.
        !           262: The only way to create a new process on Unix, though, is for
        !           263: an existing process to make a copy of itself by executing
        !           264: a program statement called fork.
        !           265: The new and old processes are identical except that one knows
        !           266: it is a parent and the other knows it is a child, and
        !           267: the internal code of the program for both processes can
        !           268: take different branches on the basis of this information.
        !           269: This step is time-consuming, and the documentation sometimes
        !           270: mentions useful ways to avoid having to fork new processes,
        !           271: for instance, by using built-in commands.
        !           272: 
        !           273: [5] The child sets up input and output.
        !           274: 
        !           275: In this step, the command words are scanned for special input or
        !           276: output redirection constructs.
        !           277: When these constructs have been interpreted, they are removed
        !           278: from the list of command words.
        !           279: Any output file specified is created if it does not already exist.
        !           280: If the file or directory does not have the correct permissions,
        !           281: or an input file does not exist, the shell, not the program named
        !           282: by the first command word, issues an error message and prompts
        !           283: for another command.
        !           284: The program to be run has no knowledge that its inputs and outputs
        !           285: have been changed.
        !           286: 
        !           287: In the presence of a pipe between commands, the shell removes the
        !           288: pipe constructs from the command line after first breaking it up
        !           289: into separate subcommands.  Each of these subcommands is processed
        !           290: like any other command, with a separate fork and execl for each.
        !           291: The main difference is that the parent sets up input and output
        !           292: between processes and has them all started up before beginning
        !           293: to wait on any of them.
        !           294: 
        !           295: [6] The child transforms itself into the program found in step 3.
        !           296: 
        !           297: This is where the child does the execl, but not precisely.
        !           298: For simplicity I did not mention that the actual call is
        !           299: of the form:  execve( PROGFILE, ARG0, ARG1, ARG2, ..., 0 , ENV0, ENV1,
        !           300: ENV2, ..., 0 ).
        !           301: The new arguments (after the first 0) contain definitions of
        !           302: all the current process's environment variables.
        !           303: These may contain any information the user may choose
        !           304: to store in them using the built-in command "setenv" and
        !           305: have the property that besides input/output redirection, the
        !           306: current directory, and a handful of other data,
        !           307: they are some of the very few things
        !           308: that can be inherited by the new program after execl.
        !           309: 
        !           310: [7] The child dies.
        !           311: 
        !           312: Processes can finish normally or abnormally,
        !           313: but all of them die eventually.
        !           314: For example, when you leave "vi" by typing ZZ, or when
        !           315: "nroff" stops because of a macro/diversion overflow,
        !           316: then the associated processes die.
        !           317: Your shell itself is a process which dies when you logout.
        !           318: 
        !           319: When the child process running the new program dies,
        !           320: the Unix kernel sends a signal to the parent process (your shell)
        !           321: notifying it of the event.
        !           322: 
        !           323: [8] The parent waits for the child to die, then prompts the user.
        !           324: 
        !           325: In the meantime, the parent process has executed a program statement
        !           326: called wait which just puts it on hold until Unix
        !           327: sends a signal notifying the shell that the child has died.
        !           328: If you had entered an & at the end of the original command,
        !           329: your shell would not wait for notification of the child's death
        !           330: but would print the child's process number and then
        !           331: prompt you for the next command.
        !           332: That procedure is called backgrounding a process.
        !           333: 
        !           334: While the C shell is waiting for the child (only on 4.1 or 4.2 BSD Unix)
        !           335: you can type ^Z to wakeup the parent and
        !           336: freeze the child for the time being.
        !           337: At that point you could enter other commands to shell and
        !           338: at a later time you could issue commands to resume execution,
        !           339: kill it altogether, or resume execution in the background.
        !           340: This useful feature is called job control.
        !           341: 
        !           342: 
        !           343: jak

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.