home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  

UNIX Power Tools

UNIX Power ToolsSearch this book
Previous: 8.4 Command Evaluation and Accidentally Overwriting Files Chapter 8
How the Shell Interprets What You Type
Next: 8.6 Output Command-Line Arguments

8.5 Command-Line Evaluation

With all the different substitution mechanisms available in the C shell, it's important to know which take precedence. Here's the order in which the C shell interprets the command line:

  1. History substitution

  2. Splitting words (including special characters)

  3. Updating the history list

  4. Interpreting single quotes ( ' ) and double quotes ( " )

  5. Alias substitution

  6. Redirection of input and output ( e.g., > , < , and | )

  7. Variable substitution

  8. Command substitution

  9. Filename expansion

(The Bourne shell is essentially the same, except that it doesn't perform history substitution or alias substitution.)

History substitutions are always done first. That's why quotes won't protect a ! from the shell; the shell sees the exclamation point and substitutes a command from the history before it's even thought about the quotation marks. To prevent history substitution, you need to use a backslash ( 8.15 ) .

Let's work through a simple command line that uses several of these features. Nothing in this command line will be difficult, but it will give you a feeling for what we mean by saying that "the shell performs variable substitution after alias substitution." Here's the command line; it has both space and TAB characters:


ls -l    $HOME/* |     grep "Mar  7"

And here's what happens:

  1. There are no history operators, so history substitution ( 11.2 ) doesn't happen. (The Bourne shell wouldn't perform this step.)

  2. The command line is split into separate "words" at the whitespace characters. The words are ls , -l , $HOME/* , | , grep , and "Mar  7" . The shell ignores the amount of whitespace (spaces and TABs) between different words in a command line. Any unquoted whitespace creates a new word. The shell doesn't do anything special with options (like -l ). Options are passed to the command being run, just like any other word; [2] the command decides how to interpret them. Also, note that quotes ( 8.14 ) prevent the shell from splitting "Mar  7" into two words or eating the two spaces - even though quote interpretation comes later. [3] At this point, the command line looks like this:

    [2] The convention of starting options with a dash ( - ) is just that: a convention. Although option handling is being standardized ( 44.18 ) , each command can interpret its options any way it wants to.

    [3] In an ls -l listing, dates less than 10 have two spaces before them (they're printed in a field 2 characters wide).

    ls -l $HOME/* | grep "Mar  7"

  3. The shell sticks the command line onto the history list. The Bourne shell wouldn't perform this step, either.

  4. The shell recognizes the double quotes around "Mar  7" and notes that wildcard expansion (yet to come) shouldn't take place inside the quotes.

  5. The shell checks whether or not ls or grep are aliases ( 10.2 ) . They could be, but we're assuming they aren't.

  6. The shell notices the | , and does whatever's required ( 13.1 ) to set up a pipeline.

  7. The shell notices the environment variable ( 6.1 ) $HOME , and replaces this variable with its value ( /home/mikel ). At this point, the command line looks like:

    ls -l /home/mikel/* | grep "Mar  7"

  8. The shell looks for backquotes ( 9.16 ) , executes any command inside the backquotes, and inserts its output on the command line. In this case, there's nothing to do. (If there are wildcards or variables inside the backquotes, they aren't interpreted before the shell runs the command inside the backquotes.)

  9. The shell looks for wildcards ( 1.16 ) . In this case, it sees the * and expands the filename accordingly, leaving something like this:

    ls -l /home/mikel/ax ... /home/mikel/zip | grep "Mar  7"

  10. The shell executes the ls command, executes the grep command, with the aforementioned pipe sending the ls output into grep 's input.

One character you'll see often on command lines is ; (semicolon). It's used as a command separator: type one complete command line - then, instead of pressing RETURN, type a semicolon and another complete command line. Chaining commands with semicolons is especially useful in subshells ( 13.7 ) , aliases, and lists ( 13.8 ) - this book has lots of examples - in articles 40.2 and 10.2 , for instance. There's more about command-line interpretation in the articles on wildcards inside aliases ( 8.9 ) , eval ( 8.10 ) , conditional execution ( 44.9 ) , and many others. [For some nitty-gritty details about the C shell that are fun, too, I recommend Chris Torek's article 8.12 . - JP  ]

- DG , ML

Previous: 8.4 Command Evaluation and Accidentally Overwriting Files UNIX Power Tools Next: 8.6 Output Command-Line Arguments
8.4 Command Evaluation and Accidentally Overwriting Files Book Index 8.6 Output Command-Line Arguments

The UNIX CD Bookshelf Navigation The UNIX CD BookshelfUNIX Power ToolsUNIX in a NutshellLearning the vi Editorsed & awkLearning the Korn ShellLearning the UNIX Operating System