![]()
by John Valley and Sean Drew
As a UNIX user, you have a wide variety of shells available to you: the Bourne shell, Bourne Again shell, POSIX shell, C shell, TC shell, Z shell, and Korn shell. Although this is not an all encompassing list of available shells, it does cover the more commonly used shells. Most UNIX systems come pre-installed with some subset of the shells mentioned. If you wish to use a shell that was not pre-installed on your system, you will more than likely find the one you want on the Internet. The C shell--the subject of this chapter--is one of the more popular and widely available shells in UNIX. It was developed after the Bourne shell but before the Korn shell. The C shell incorporates many features of the Bourne shell and adds many new ones that make your UNIX sessions more efficient and convenient.
Each shell has certain advantages and disadvantages. You might want to review Chapter 13, "Shell Comparison," to help you decide which one to use.
The C shell, written by Bill Joy (also the author of the vi text editor), was not patterned after the Bourne shell. Bill chose the C programming language as a syntax model. The C shell commands--especially if, while, and the other structured programming statements--are somewhat similar in syntax to the equivalent statements in C. A shell is quite a different animal from a compiler, though, so the C programming language served only as a model; many forms and structures in the C shell have nothing to do with the C programming language.
Because the C shell is not just an extension of the Bourne shell syntax, this chapter will cover all aspects of C shell operation. You therefore can read it independently of Chapter 9, "The Bourne Shell," Chapter 10, "The Bourne Again Shell," and Chapter 11, "The Korn Shell."
Each time you log onto UNIX, you're placed in an interactive shell referred to as your logon shell. If your logon shell is using the default prompts, you can tell if your logon shell is the C shell by its command-line prompt: the percent sign (%). The default C shell prompt differs from the default dollar-sign prompt ($) of the Bourne shell to remind you that you're using the C shell. You can customize your command-line prompt when using the C shell; for more information, see the definition of prompt in "Variables," later in this chapter.
The most foolproof way to determine your logon shell is to query the passwd file. The seventh field contains the path to your logon shell. The command
grep 'whoami' /etc/passwd |cut -f7 -d:
will print the path of your logon shell. If you are using Network Information Service (NIS) to manage user information, the /etc/passwd file is not accessible, so the command
ypcat passwd |grep 'whoami' |cut -f7 -d:
will do the trick.
If your logon shell is not the C shell, and the C shell is available on your system, you can invoke it as an interactive shell from the command-line. Even when you're already running the C shell, there will be times when you want to launch the C shell again--for example, to run a shell script or to temporarily change the shell's options. To invoke the C shell interactively, use this command:
$ csh %
NOTE: The csh command usually is located in the /bin or /usr/bin directory. Because both directories are usually in your search path, you shouldn't have any trouble finding the csh command if your system has it. If you don't find it right away, you might look in the directory /usr/ucb (the standard home for BSD components in a UNIX System V system) or in /usr/local/bin. /usr/local/bin is a home for programs your site has acquired that were not provided with the original system software. Remember that, for many years, the C shell was available only to those sites using the BSD variant of UNIX; unlike the Bourne shell, there is no guarantee that you will have the csh command on your system.
The csh command also supports a number of options and arguments (described later in this chapter in "Shell Options"), but most options are not relevant to running an interactive shell.
Whenever csh is invoked, whether as the logon shell or as a subshell, it loads and executes a profile script named .cshrc. If it is a logon shell, the C shell also executes a profile script on startup named .login and another on exit named .logout. Note that the .login script is executed after .cshrc--not before. For additional information about C shell profile scripts, see "Customizing Your Shell Environment," later in this chapter.
Most versions of the C shell import environment variables such as PATH into local array variables at startup. The C shell does not refer to the public environment variables (including PATH) for its own operation. This means that you'll usually want to maintain the path variable for directory searches--not PATH. Some versions of the C shell do not properly import environment variables, which can give you confusing results. If it appears that you have no search path set, but the PATH variable is set and accurate (as shown by echo $PATH), check that the variable path has a matching value. If not, you'll need to import critical environment variables into local variables yourself.
NOTE: If you are familiar with the Bourne shell, you won't notice much difference when working with the C shell unless you use advanced shell features such as variables, command replacement, and so on.
Important differences do exist, however. Among these are the set of punctuation characters that have a special meaning to the shell (often called metacharacters). The C shell is sensitive to all the special characters of the Bourne shell, as well as the tilde (~), the commercial at sign (@), and the exclamation point (!). Don't forget to quote or escape these characters when writing commands unless you intend to use their special shell meaning. (See "Quoting and Escaping from Special Characters," later in this chapter, for a discussion of the details.)
When you enter commands at the shell prompt, you are providing input to the shell. The shell sees a line of input as a string of characters terminated with a newline character; the newline is usually the result of pressing Enter on your keyboard. Input to the C shell can be anything from a single, simple command to multiple commands joined with command operators. Each command line you enter is actually a shell statement. In addition to providing input to the shell manually by entering shell statements on the command line, you can provide input to the shell by putting shell statements into a file and executing the file. Files of shell statements commonly are known as shell scripts.
This section covers the basics of interacting with the shell by entering shell statements on the command line. (Of course, anything you can enter on the command line also can be put into a file for later, "canned" execution.) The subsection "Shell Statements: A Closer Look," provides a more detailed, technical look at the components of shell statements. If you plan to write shell scripts, you'll definitely want to read this section.
When you finish this section, you will feel like you know a good deal about the C shell, but this is really just the beginning. In addition to the C shell's basic service of providing a means to instruct the computer, the C shell also provides a number of tools you can use to expedite your work flow. These tools or features of the shell are described in subsequent sections of this chapter.
The C shell accepts several types of commands as input: UNIX commands, built-in shell commands, user-written commands, and command aliases. This section describes the types of commands you can execute and the ways you can execute them.
Command Names as Shell Input A command is executed by entering the command's name on the command-line. The C shell supports any of the following as command names:
Built-In Shell Commands C shell provides a number of commands implemented within the shell program. Built-in commands execute very quickly, because no external program file needs to be loaded. Table 12.1 lists the built-in C shell commands. The remainder of this chapter groups these commands into subsections dedicated to particular tasks you'll perform in the shell and describes how to use each command.
| Command | Description |
| alias | Defines or lists a command alias |
| bg | Switches a job to background execution |
| break | Breaks out of a loop |
| breaksw | Exits from a switch statement |
| case | Begins a case in switch |
| cd | Changes directory |
| chdir | Changes directory |
| continue | Begins the next loop iteration immediately |
| default | Specifies the default case in switch |
| dirs | Lists the directory stack |
| echo | Echoes arguments to standard output |
| eval | Rescans a line for substitutions |
| exec | Replaces the current process with a new process |
| exit | Exits from the current shell |
| fg | Switches a job to foreground execution |
| foreach | Specifies a looping control statement |
| glob | Echoes arguments to standard output |
| goto | Alters the order of command execution |
| hashstat | Prints hash table statistics |
| history | Lists the command history |
| if | Specifies conditional execution |
| jobs | Lists active jobs |
| kill | Signals a process |
| limit | Respecifies maximum resource limits |
| login | Invokes the system logon procedure |
| logout | Exits from a logon shell |
| newgrp | Changes your Group ID |
| nice | Controls background process dispatch priority |
| nohup | Prevents termination on logout |
| notify | Requests notification of background job status changes |
| onintr | Processes an interrupt within a shell script |
| popd | Returns to a previous directory |
| pushd | Changes directory with pushdown stack |
| rehash | Rehashes the directory search path |
| repeat | Executes a command repeatedly |
| set | Displays or changes a shell variable |
| setenv | Sets environment variable |
| shift | Shifts parameters |
| source | Interprets a script in the current shell |
| stop | Stops a background job |
| suspend | Stops the current shell |
| switch | Specifies conditional execution |
| time | Times a command |
| umask | Displays or sets the process file-creation mask |
| unalias | Deletes a command alias |
| unhash | Disables use of the hash table |
| unlimit | Cancels a previous limit command |
| unset | Deletes shell variables |
| unsetenv | Deletes environment variables |
| wait | Waits for background jobs to finish |
| while | Specifies a looping control |
| %job | Specifies foreground execution |
| @ | Specifies expression evaluation |
Executing Simple Commands The most common form of input to the shell is the simple command, where a command name is followed by any number of arguments. In the following command line, for example, ftp is the command and hostname is the argument:
% ftp hostname
It is the responsibility of the command, not the shell, to interpret the arguments. Many commands, but certainly not all, take this form:
% command -options filenames
Although the shell does not interpret the arguments of the command, the shell does interpret some of the input line before passing the arguments to the command. Special characters entered on a command line tell the shell to redirect input and output, start a different command, search the directories for filename patterns, substitute variable data, and substitute the output of other commands.
Entering Multiple Commands on One Line Ordinarily, the shell interprets the first word of command input as the command name and the rest of the input as arguments to that command. The semicolon (;) directs the shell to interpret the word following the symbol as a new command, with the rest of the input as arguments to the new command. For example, the command line
% echo "<h1>" ; getTitle; echo "</h1>"
is the equivalent of
% echo "<h1>" % getTitle % echo "</h1>"
except that, in the second case, the results of each command appear between the command input lines.
When the semicolon is used to separate commands on a line, the commands are executed in sequence. The shell waits until one command is complete before executing the next command. You also can execute commands simultaneously (see "Executing Commands in the Background," later in this chapter) or execute them conditionally, which means that the shell executes the next command if the command's return status matches the condition (see "Executing Commands Conditionally," later in this chapter).
Entering Commands Too Long for One Line Command lines can get quite lengthy. Editing and printing scripts is easier if command lines are less than 80 characters, the standard terminal width. Entering commands that span multiple lines is accomplished by escaping the newline character, as in the following command, which translates some common HTML sequences back to a readable format:
% sed -e "s/%3A/:/" -e "s@%2F@/@g" -e "s@%3C@<@g" \ -e 's/%5C/\\/g' -e "s/%23/#/g" -e "s/%28/(/g" \ -e "s/%29/)/g" -e "s/%27/'/g" -e 's/%22/\"/g' infile > outfile
The shell sees a line of input as a statement terminated with a newline character; however, the newline character also is considered to be a white-space character. If you end a line with a backslash (\), the next character--the newline character--is treated literally, which means that the shell does not interpret the newline character as the end of the line of input.
Executing Commands in the Background Normally, when you execute commands, they are executed in the foreground. This means that the C shell will not process any other commands, and you cannot do anything else until the command finishes executing. If waiting for long commands to complete is not in your top 10 list of things to do, you can have your current shell handle more commands without waiting for a command to finish. You can execute the command in the background by putting an ampersand (&) at the end of the command:
% find . -name "*.c" -print & [2] 13802 %
You also can run multiple commands in the background simultaneously:
% xterm & xclock & xload &
A command executing in the background is referred to as a job, and each job is assigned a job number--the bracketed number in the previous example. The C shell provides you with several commands for managing background jobs; see "Job Control," later in this chapter, for more information.
Repeatedly Executing a Command: repeat You can use the repeat command to execute some other command a specified number of times. Although the repeat command isn't used frequently, it can be quite handy on occasion. If you are writing a shell script to print a document, for example, you might use the command
repeat 5 echo ################################
to mark its first page clearly as the start of the document.
The syntax of the repeat command follows:
repeat count command
For count, specify a decimal integer number. A count of zero is valid and suppresses execution of the command.
For command, specify a simple command that is subject to the same restrictions as the first format of the if statement. The command is scanned for variable, command, and history substitutions; filename patterns; and quoting. It cannot be a compound command (foo;bar), a pipeline (foo|bar), a statement group (using {}), or a parenthesized command list ( (foo;bar|bas) ).
Any I/O redirections are performed only once, regardless of the value of count. For example,
repeat 10 echo Hello >hello.list
results in 10 lines of Hello in a file named hello.list.
Executing Commands in a Subshell: () A command (or a list of commands separated by semicolons) enclosed in parentheses groups the command or commands for execution in a subshell. A subshell is a secondary invocation of the shell, so any change to shell variables, the current directory, or other such process information lasts only while executing the commands in the subshell. This is a handy way, for example, to switch to another directory, execute a command or two, and then switch back without having to restore your current directory:
% (cd /usr/local/etc/httpd/htdocs; cp *.html /users/dylan/docs)
Without the parentheses, you would have to write this:
% cd /usr/local/etc/httpd/htdocs % cp *.html /users/dylan/docs % cd /previous/directory
The syntax for grouping commands follows:
( commands )
Enclosing a list of commands in parentheses is a way to override the default precedence rules for the &&, ||, and | operators, at the expense of invoking a subshell and losing any environmental effects of the commands' execution. For example, (grep || echo) | pr pipes the output of the grep command, and possibly that of echo if grep sets a nonzero exit code, to the pr command.
I/O redirections can be appended to the subshell just as for a simple command; the redirections are in effect for all the commands within the subshell. For example,
(cat; echo; date) > out
writes the output of the cat, echo, and date commands to a file named out without any breaks. If you look at the file afterward, first you'll see the lines written by cat, followed by the lines written by echo, and finally the lines written by date. Similarly, input redirections apply to all commands in the subshell, so that each command in turn reads lines from the redirected file, starting with the line following those read by any previously executed commands in the subshell.
Executing Commands Conditionally Compound commands are actually two or more commands combined so that the shell executes all of them before prompting for (or, in the case of shell scripts, reading) more input.
Compound commands are not often needed for interactive work. Compound commands form a very useful extension to the C shell's syntax, however, especially in shell scripts. Some compound command formats, such as & (background job) and | (the pipe operator) are essential to work effectively with UNIX.
Conditional Execution on Success: && (And) You use the double ampersand operator (read and) to join two commands: command1 && command2. It causes the shell to execute command2 only if command1 is successful (that is, command1 has an exit code of zero).
For command1 or command2, you can write a simple command or a compound command. The && operator has higher precedence than || but lower precedence than |. For example,
grep mailto *.html | pr && echo OK
echoes OK only if the pipeline grep | pr sets a zero exit code. (For pipelines, the exit code is the exit code of the last command in the pipeline.)
The compound command
tar cvf docs.tar docs && rm -rf docs
shows one possible benefit of using &&: The rm command deletes the docs directory only if it first is backed up successfully in a tar file.
Conditional Execution on Failure: || (Or) You use the or operator to join two commands: command1 || command2. It causes the shell to execute command2 only if command1 failed (that is, returned a nonzero exit code).
For command1 or command2, you can write a simple command or a compound command. The || operator has lower precedence than both the && and | operators. For example, in the following command
grep mailto *.html || echo No mailto found | pr
either grep succeeds and its output is placed to standard output, or the words No mailto found are piped to the pr command.
Use the || operator to provide an alternative action. In the following case, if the mkdir command fails, the exit command prevents further execution of the shell script:
mkdir $tmpfile || exit
A command is a basic command or a basic command embellished with one or more I/O redirections.
A basic command is a series of words, each subject to replacements by the C shell, which, when fully resolved, specifies an action to be executed and provides zero or more options and arguments to modify or control the action taken. The first word of a basic command, sometimes called the command name, must specify the required action.
In plainer terms, a statement is the smallest executable unit. When the shell is operating in interactive mode, it displays its prompt when it requires a statement. You must continue to enter shell statement components, using multiple lines if necessary, until you complete a full statement. If the statement is not completed on one line, the shell continues to prompt you, without executing the line or lines you have entered, until it receives a full statement.
Shell statements are formed from a number of tokens. A token is a basic syntactic element and can be any of the following:
Filename generation using patterns is an important facility of the Bourne shell. The C shell supports the filename patterns of the Bourne shell and adds the use of {} (braces) to allow greater flexibility. Globbing also is known as wildcarding.
Several shell commands and contexts allow the use of pattern-matching strings, such as the case statement of switch and the =~ and !~ expression operators. In these cases, pattern strings are formed using the same rules as for filename generation, except that the patterns are matched to another string.
When any of the pattern expressions described in Table 12.2 are used as arguments of a command, the entire pattern string is replaced with the filenames or pathnames that match the pattern. By default, the shell searches the current directory for matching filenames, but if the pattern string contains slashes (/), it searches the specified directory or directories instead. Note that several directories can be searched for matching files in a single pattern string: a pattern of the form dir/*/*.cc searches all the directories contained in dir for files ending with .cc.
| Expression | Definition |
| * | The asterisk, also known as a star or splat, matches any string of characters, including a null string (the asterisk matches zero or more characters). When the asterisk is used by itself, it matches all filenames. When the asterisk is used at the beginning of a pattern string, leading prefixes of the filename pattern are ignored: *.cc matches any filename ending with .cc. When the asterisk is used at the end of a pattern string, trailing suffixes of the filename pattern are ignored: foo* matches foo.cc, foobar.html, and any filename beginning with foo. An asterisk in the middle of a pattern means that matching filenames must begin and end as shown but can contain any character sequences in the middle: pay*.cc matches filenames beginning with pay and ending with .cc, such as payroll.cc, paymast.cc, and paycheck.cc. Multiple asterisks can be used in a pattern: *s* matches any filename containing an s, such as sean.txt or apps.hh. |
| ? | The question mark matches any one character. For example, ? as a complete word matches all filenames one character long in the current directory. The pattern pay?.cc matches pay1.cc and pay2.cc but not payroll.cc. Multiple question marks can be used to indicate a specific number of don't-care positions in the filename: pay.?? matches filenames beginning with pay. and ending in any two characters, such as pay.cc and pay.hh, but does not match pay.o. |
| [] | The square brackets enclose a list of characters. Matching filenames contain one of the indicated characters in the corresponding position of the filename. For example, [abc]* matches any filename beginning with the letter a, b, or c. Because of the asterisk, the first character can be followed by any sequence of characters. |
| Use a hyphen (-) to indicate a range of characters. For example, pay[1-3].c matches filenames pay1.cc, pay2.cc, and pay3.cc, but not pay4.cc or pay11.cc. Multiple ranges can be used in a single bracketed list. For example, [A-Za-z0-9]* matches any filename beginning with a letter or a digit. To match a hyphen, list the hyphen at the beginning or end of the character list: [-abc] or [abc-] matches an a, b, c, or hyphen. | |
| ~ | The tilde (~) can be used at the beginning of a word to invoke directory substitution of your home directory. The (~) is substituted with the full pathname of your home directory. Also used in the form ~/path to refer to a file or directory under your home directory. If the tilde does not appear by itself as a word and is not followed by a letter or a slash, or it appears in any position other than the first, it is not replaced with the user's home directory. Thus, /usr/rothse/file.cc~ is a reference to the file file.cc~ in the directory /usr/rothse. |
| ~name | Substituted with the full pathname of user name's home directory. For example, ~ken/bin refers to /usr/ken/bin if the home directory for user ken is /usr/ken. The password file /etc/passwd is searched for name to determine the directory pathname; if name is not found, the shell generates an error message and stops. |
| {} | Braces enclose a list of patterns separated by commas. The brace expression matches filenames having any one of the listed patterns in the corresponding position of the name. For example, the pattern |
| /usr/home/{kookla,fran,ollie}/.cshrc | |
| expands to the path list | |
| /usr/home/kookla/.cshrc /usr/home/fran/.cshrc /usr/home/ollie/.cshrc | |
| Unlike *, ?, and [], brace-enclosed lists are not matched against existing filenames; they simply are expanded into words subject to further substitution regardless of whether the corresponding files exist. Brace-enclosed lists can be nested--for example, /usr/{bin,lib,home/{john,bill}} refers to any of the directories /usr/bin, /usr/lib, /usr/home/john, and /usr/home/bill. |
It is important to realize that filename generation using pattern strings can cause a replacement of one word with many. A filename pattern must be a single word. The ordinary characters and pattern-matching characters in the word describe a rule for choosing filenames from the current or specified directory. The word is replaced with each filename or pathname found that matches the pattern. If you had three files in your current directory (ch1.txt, ch2.txt and chlast.txt), then the pattern *.txt would expand to match those three files:
% echo Files: *.txt Files: ch1.txt ch2.txt chlast.txt
You can use pattern expansion in many ways; for example, the expansion below is used to set a shell variable to be an array of three items. The array is then queried for its length and second element. See "Using Array Variables" later in this chapter, for more information about C shell arrays.
% set files=(*.txt) % echo Found $#files files Found 3 files % echo $files[2] ch2.txt
TIP: Another powerful C shell feature for determining files in a directory is the command/filename viewing feature that uses control D (Ctrl-D). This feature enables you to determine the files available for a command without aborting the command. For example, if you type cp ~sdrew/docs/ind and want to see which files match the specification, pressing Ctrl-D displays a list of matching files in a multicolumn format. Certain files have a character appended to indicate the file type (this behavior is similar to the output of ls -F): executables are marked with an asterisk (*), directories are marked with a slash (/), and links are marked with an at sign (@). After the column-sorted list is displayed, the command is redisplayed so that you can continue typing. The files listed will be those that match the pattern ~sdrew/docs/ind*. Note that ~(Ctrl-D) prints a list of all users who have accounts on the system.
Commands can be completed in a similar manner if the C shell is expecting a command as part of your current input. The current command pattern is looked for in each directory specified in the PATH environment variable. Note that aliases are not expanded by Ctrl-D. If my PATH is set to /bin:~/bin:/usr/bin and I complete the command pri using Ctrl-D, the output is roughly the same as ls /bin/pri* ~/bin/pri* /usr/bin/pri*.
In addition to getting lists of commands and filenames, the Escape (ESC) key can be used to complete partially typed commands and filenames. The automatic completions are known as command completion and filename completion, depending on whether you are completing a filename or a command. The pattern matching is done as in the Ctrl-D viewing utility. If the partial name is unique, the name is completed; otherwise, the terminal bell is sounded. If ambiguities are encountered (that is, more than one file matches), the name is completed to the ambiguity, and the terminal bell is sounded. Suppose you had two files in a directory named veryLongName.txt and veryLong_Name.txt and you wanted to edit the file veryLong_Name.txt, you can save yourself a great deal of typing by using filename completion. You can type vi ve(Esc), which completes to vi veryLong and rings the bell. Then, if you type _(Esc), the name completes to vi veryLong_Name.txt, at which point you can press Enter and begin your vi session.
The C shell provides several commands for redirecting the input and output of commands. You might be familiar with the input (<) or output (>) redirection characters from earlier chapters. The C shell provides you with these and more.
An I/O redirection is an instruction to the shell you append to a command. It causes one of the standard file descriptors to be assigned to a specific file. You might have encountered standard files in the discussion of the Bourne shell in Chapter 9. The UNIX operating system defines three standard file descriptors: standard input (stdin), standard output (stdin), and standard error (stderr).
NOTE: The UNIX operating system actually provides at least 25 file descriptors for use by a command. It is only by convention that the first three are set aside for reading input, writing output, and printing error messages. Unless you instruct otherwise, the shell always opens these three file descriptors before executing a command and assigns them all to your terminal.
A file descriptor is not the file itself; it is a channel, much like the audio jack on the back of your stereo--you can connect it to any audio source you want. Similarly, a file descriptor such as standard input must be connected to a file--your terminal by default, or the disk file or readable device of your choice.
You can change the location where a command reads data, writes output, and prints error messages by using one or more of the I/O redirection operators. Table 12.3 lists the operators.
| Format | Effect |
|
Input Redirection |
|
| < filename | Uses the contents of filename as input to a command. |
| << word | Provides shell input lines as command input. Lines of the shell input that follow the line containing this redirection operator are read and saved by the shell in a temporary file. Reading stops when the shell finds a line beginning with word. The saved lines then become the input to the command. The lines read and saved are effectively deleted from the shell input and are not executed as commands; they are "eaten" by the << operator. Shell execution continues with the line following the line beginning with word. If you use the << operator on a command you type at the terminal, be careful: Lines you type afterward are gobbled up by the shell--not executed--until you enter a line beginning with whatever you specified as word. The << operator most often is used in shell scripts. This technique is known as providing a here document. |
|
Output Redirection |
|
|
> filename |
Writes command output to filename. |
|
>! filename |
Writes command output to filename and ignores the noclobber option. The noclobber option is fully explained in "Using Predefined Variables," later in this chapter. Briefly, noclobber causes the shell to disallow the > filename redirection when filename already exists; noclobber is therefore a safety you can use to prevent accidentally destroying an existing file. Sometimes, you will want to redirect output to a file even though it already exists. In such a case, you must use the >! operator to tell the shell you really want to proceed with the redirection. If you don't set the noclobber option, you don't need to use the >! operator. |
|
>& filename |
Writes both the command output and error messages to filename. |
|
>&! filename |
Writes both the command output and error messages to filename and ignores the noclobber option. |
|
>> filename |
Writes command output at the end of filename (Append mode). |
|
>>! filename |
Writes command output at the end of filename (Append mode) and ignores the noclobber option. |
|
>>& filename |
Writes command output and error messages at the end of filename (Append mode). |
|
>>&! filename |
Writes command output and error messages at the end of the filename (Append mode) and ignores the noclobber option. |
In Table 12.3, filename represents any ordinary filename or pathname; or any filename or pathname resulting after variable substitution, command substitution, or filename generation.
I/O redirection operators are appended to a command; for example, date >curdate writes the current date to the file curdate instead of to your terminal. You also can use more than one redirection per command: Simply list them one after another at the end of the command. The order doesn't matter: for example, both cat <infile >outfile and cat >outfile <infile have the same effect.
Input Redirection Some commands make no special use of the standard input file, such as the date and the ls system commands; others require an input file to function properly, such as the cat and awk commands. You can use the < redirection operator in the form command < filename to designate a file as the source of input for commands such as cat and awk; if you do not, these commands read data from your keyboard--sometimes useful, but usually not. If you provide an input redirection, but the command does not read data (such as ls), the I/O redirection still is performed by the shell; it is just ignored by the command. Note that it is an error to redirect standard input to a file that doesn't exist.
The redirection << word is a special form of the input-redirection operator. Instead of taking input from a file, input to the command comes from the current shell input stream--your keyboard, if you append << to a command you type in, or your shell script if you use << on a command in a shell script.
For word, you choose an arbitrary string to delimit the lines of input. Then write the lines to be provided to the command as input immediately following the command line, and follow the last line of desired input with a line beginning with word. The shell reads the lines up to word, stores the lines in a temporary file, and sets up the temporary file as standard input for the command.
The << word form of input redirection is called a here document, because it is located here, in line with your shell commands. Here documents are useful when you want to provide predefined data to a command, and they save you from having to create a file to hold the data.
Unlike the filename part of other I/O redirection operators, word for the here document is not scanned for variable references, command substitutions, or filename patterns; it is used as is. All the following shell input lines are checked for the presence of word as the only word on the line before any substitutions or replacements are performed on the line.
Normally, lines of the here document are checked for variable references and command replacements; this enables you to encode variable information in the here document. If you quote any part of word, however, the lines are read and passed to the command without modification. The redirection << STOP reads lines up to STOP and performs substitutions on the lines it reads, for example. The redirection << "STOP" reads lines up to the line beginning with STOP and passes the lines directly to the command, as they are, without substitutions or replacements of any kind.
The line beginning with word is discarded; it is not passed to the command in the here document or executed by the shell.
The following example shows the use of a here document to create an HTML form:
cat <<HERE <FORM method=post action=http://host.com/cgi-bin/addTime.sh> <select NAME=username> ´´./doUserQuery;./parseList.sh users_$$.txt "$userName"´´ </select> <input type=submit value=Submit> </form> HERE
The line containing the word HERE will not appear in the output; it is simply a mark to let the shell know where the redirected lines end.
Output Redirection Output redirections have the general form > filename and >> filename. The first operator creates a new file of the specified filename. The file is opened before command execution begins, so even if the command fails or cannot be found, or if the shell finds an error on the command line and stops, the output file still is created.
NOTE: For purposes of understanding shell syntax, you should note that appending an I/O redirection to a simple command yields a simple command. Except where specifically prohibited, a command with redirections appended can be used wherever a simple command is allowed, such as on the single-line if statement.
If you've set the noclobber option (with set noclobber), the shell refuses to create the named output file if it already exists; doing so would destroy the file's current contents. If you want to perform the output redirection even if the file filename already exists, use the redirection operator >! instead; it overrides the noclobber option.
The >> command arranges for command output to be added to the end of the named file. For this redirection operator, the noclobber option requires that the named file already exist. If you use the alternative form >>!, or if you use >> and the noclobber option is not set, the shell creates the named file if necessary.
The >& and >>& operators redirect both the standard output and standard error files to filename. The Bourne shell enables you to redirect the standard output and standard error files separately; the C shell does not.
TIP: Although the C shell offers no direct means for redirecting standard error and standard output at the same time, you can achieve the net result at the expense of a subshell. In the subshell, redirect standard output via the > operator to the desired location for non-error messages and then redirect standard error and standard output from the subshell via the >& operator to the desired location for error messages. Because the standard output was redirected in the subshell, the standard output and standard error redirection from the subshell will contain only the standard error.
Suppose that you want to run a script, buildSystem, that builds a large software class library and generates nearly 1MB of output, of which a few messages might be errors. The following command places standard output in a file named build.log and error messages from standard error in buildErr.log:
As you saw in previous sections, certain characters have special meanings for the shell. When the shell encounters a special character, the shell performs the action defined by the special character. The following punctuation characters available on the standard keyboard are special to the shell and disrupt the scanning of ordinary words:
~ ' ! @ # $ % ^ & * ( ) \ | { } [ ] ; ' " < > ?
In some contexts, particularly within the switch statement, the colon (:) is also a special character. The colon is recognized as a special character only when expected, in a case or default statement, and as a statement label. It does not need to be quoted except to avoid these specific interpretations.
To use one of these characters as a part of a word without its special significance, you can escape the character by placing a backslash (\) immediately in front of the character. Note that a backslash intended as an ordinary character must be written as two backslashes in succession: \\. To escape a two-character operator such as >>, you must insert a backslash in front of each character: \>\>. The $ character can be escaped if followed by white space:
% echo escaped $ sign escaped $ sign
Alternatively, you can enclose the special character or any portion of a word containing the special character in quotes. The C shell recognizes three kinds of quotes: the apostrophe ('), the quote ("), and the backquote (´´). The C shell does not consider the enclosing quotes as part of the input passed to commands. The output for
% echo "Enter name>" Enter name>
does not contain quotes. Use two apostrophes (also called single quotes, foreticks, or just simply ticks) to enclose a character sequence and avoid all interpretation by the shell. I often call a string enclosed in apostrophes a hard-quoted string, because the shell performs absolutely no substitution, replacement, or special interpretation of characters that appear between the apostrophes (except for history substitutions). Even the backslash character is treated as an ordinary character, so there are no escapes (except for \ newline and \!) within an apostrophe-enclosed string. As a result, you cannot embed an apostrophe in such a string. That is, the string 'who's there' causes a shell error; the C shell interprets the string as who concatenated with an s, followed by a white-space delimiter, followed by there, and then the starting apostrophe of another string. When the shell does not find the matching apostrophe, an error is generated: Unmatched '..
One of the uses of quoted strings is to specify a single word containing blanks, tabs, and newline characters. The following code, for example, shows the use of a single echo command to print two lines of output:
% echo -n 'Hello.\ Please enter your name: ' Hello. Please enter your name:
The double apostrophe or quote (") also provides a special bracket for character strings. The quote hides most special characters from the shell's observation. Quoted strings are subject to two kinds of scan and replacement: variable references and command substitutions.
Any of the reference forms for shell variables ($1, $name, ${name}, $name[index], $*, and others) are recognized inside quoted strings and are replaced with the corresponding string value. The replacement occurs inside the quoted string, leaving its unity as a single word intact (even if the substituted value includes blanks, tabs, or newline characters).
Command substitution occurs for strings enclosed in backquotes (´´). The entire string enclosed between matching backquotes (also known as backticks) is extracted and executed by the current shell as if it were an independent command. The command can be two or more commands separated by semicolons, a pipeline, or any form of compound statement. Any data written to standard output by the command is captured by the shell and becomes the string value of the backquoted command. The string value is parsed into words, and the series of words replaces the entire backquoted string. Using backquotes to perform command substitution can be thought of as an I/O redirection to the command line.
TIP: Although command substitution is a powerful feature of the C shell, it does have limitations. Some commands generate more output than a command line can hold, for example. (Command-line length is determined by the LINE_MAX and ARG_MAX system parameters; consult your limits man page or look over /usr/include/limits.h.) Additionally, at times, you will need to process each item of output individually, in which case command substitution is not of much use.
Suppose that you want to find all your C++ source files (*.{hh,cc}), starting from your home directory down your entire directory tree, and search the files found for the use of a certain class (RWString). The command
% grep RWString ´´find $home -name "*.[ch][ch]" -print -follow´´
generates the message /bin/grep: Arg list too long on my system. The UNIX command xargs was tailor made to solve this problem. The general use of xargs follows:
xargs reads from the standard input and places that input on the command-line of command. As many arguments as possible are passed to command on its command line. As a result, the command executed by xargs may be called multiple times in order to use up all the input read from standard input. Transforming the preceding command to use xargs results in this command:
This command produces the desired results. (Note that xargs is more efficient than the -exec option of find, because command is executed as few times as possible with as many arguments as possible. xargs -i is equivalent to the -exec option.) xargs also can be set to process each line of input individually by using the -i option, which is useful for commands that take only one argument, such as basename. When using the -i option, a replacement string--{} is the default replacement string--must be added to the command supplied for xargs to execute. The following command finds all directories that contain C++ source files:
The xargs command has a few other nifty options and is worth a perusal of your friendly local man page.
All forms of shell substitution occur inside backquoted command strings, including variable replacement, nested command executions, history substitutions, and filename patterns.
A backquoted command string (or any number of them) can appear inside a quoted string and will have its normal effect; this is the second form of substitution performed on "-quoted strings. A quoted command substitution (echo "xxx´´commands´´xxx") generates new words only at the end of each line, except at the end of the last line. If the executed command prints only one line of text, the text replaces the backquoted expression without introducing any word breaks.
Both quoting forms '...' and "..." suppress filename generation. For example, note the difference in the following echo commands:
% echo *.cc main.cc io.cc parse.cc math.cc % echo "*.cc" *.cc
Apostrophes can appear inside a double-quoted string. The apostrophe has no special significance when appearing inside a double-quoted string and does not need to be backslashed. The following example shows quotes inside quoted strings:
% echo '<input type=submit value="Return to Tracking Screen">' <input type=submit value="Return to Tracking Screen"> % echo "Your shell: '$SHELL'" Your shell: '/bin/csh'
A backslash that appears inside an apostrophe-quoted string is retained and appears in the string's value, because no substitutions occur inside an apostrophe-quoted string, as in the example below.
% echo 'Single \' quote Single \ quote
Inside a double-quoted string or a command substitution using ', or in a normal unquoted word, a backslash has the effect of suppressing shell interpretation of the character that follows it. The backslash then is removed from the string. The following examples show the effect of a backslash removing shell interpretation of quoting characters :
% echo Double \" quote Double " quote % echo Single \' quote Single ' quote
TIP: For some particularly complicated shell commands, it is necessary to get many instances of quotes and apostrophes and still have desired variable and command substitution. Simple awk commands are loaded with special shell characters, for example, and must be hard quoted:
If you want to turn this command into an alias, the combination of quotes seems impossible, because there are only two types of quotes and three levels of nesting. The following alias command yields incorrect results (note that the first command sets the alias, and the second command displays the alias):
The solution is to alternate quoting methods as needed to get the desired results. The following command alternates between using double quotes and single quotes (the portion of the command enclosed in double quotes is shown in bold, and the portion enclosed in single quotes is italicized):
The C shell provides you with several built-in commands for working with directories. The cd, chdir, pushd, and popd commands all change the current working directory.
The pushd and popd commands provide a pushdown stack mechanism for changing directories, and the dirs command displays the contents of the stack. If you switch to another directory by using pushd instead of cd, the pathname of your previous directory is "saved" in the directory stack. A subsequent popd then returns you to the previous directory. Be aware that the cd command does not maintain the directory stack; you cannot use popd to return to a directory that you left using cd.
Changing Directories: cd and chdir In the C shell, you can choose from two commands for changing your current working directory: cd and chdir. The chdir command is equivalent to cd in every way. The syntax for these commands follows:
cd [ pathname ] chdir [ pathname ]
If you omit the pathname argument, the command attempts to change to the directory whose pathname is given by the value of the C shell variable home. See "Using Predefined Variables," later in this chapter, for more information about home.
If you specify a name, the cd or chdir command uses a search hierarchy to attempt to locate the referenced directory. It follows this process:
2. The command searches your current directory. A partial pathname of the form name1/name2/namen implies searching your current directory for the entire subtree.
3. If pathname cannot be found in your current directory, the command checks to see whether the shell variable cdpath exists and has a value. If it does, each of the directories named in cdpath is checked to see whether it contains pathname. If successful, the command changes to the pathname in that directory and prints the full pathname of the new current directory.
4. If no variable cdpath exists, or if pathname cannot be found in any of the directories listed in cdpath, the command checks to see whether pathname is a variable name and has a value with / as the first character. If so, the command changes to that directory.
5. If the name still cannot be found, the command fails.
For more information about the cdpath variable, see "Using Predefined Variables," later in this chapter.
The cd and chdir commands as implemented by the C shell provide a great deal of flexibility in generating shortcuts for directory names. There is nothing more painful than having to repeatedly supply long directory names to the cd command. The purpose of the cd command's search hierarchy is to provide some mechanisms you can use for shortening a reference to a directory name. The cdpath variable is your principal tool. If you set it to a list of directories you often reference, you can switch to one of those directories just by giving the base directory name. If cdpath is not sufficiently flexible to suit your needs, you can define a shell variable as an alias for a directory's full pathname, and cd varname switches you to that directory for the price of a few keystrokes.
NOTE: When using a shell variable as a pseudonym for a directory path, you do not need to include $ in front of the variable name. Doing so is permitted and also works because of the shell's variable substitution mechanism but is not required. Only shell variables (use the set command) work as a directory alias--not environment variables (the setenv command).
Listing the Directory Stack: dirs The directory stack is a mechanism you can use to store and recall directories to which you have changed by using the special change-directory commands pushd and popd, which are discussed in the next two sections. The dirs command lists the directories in the directory stack:
% dirs /usr/local/bin ~/html/manuals /users/wadams/bin
Three directories are on the directory stack in this example. The first directory listed is the current directory (the one you see if you enter the pwd command). Directories to the right are previous directories, and the farthest to the right are the least recent. In this example, the directory /users/wadams/bin was the first directory to be changed to--that is, "pushed" onto the pushdown directory stack; ~/html/manuals was the next directory, and /usr/local/bin was the directory most recently changed to (the current directory).
Changing to a Directory by Using the Directory Stack: pushd To save the pathname of a directory on the directory stack, you can use the pushd command to change to another directory. Using pushd saves the pathname of your previous directory on the directory stack so that you can return to it quickly and easily by using the popd command. Use dirs to display the directories currently saved on the pushdown stack.
Three forms of the pushd command exist:
pushd pushd name pushd +n
Used in the form pushd, the command exchanges the top two directory-stack elements, making your previous directory the current and your current directory the previous. Successive pushd commands used without an argument switch you back and forth between the top two directories.
Used in the form pushd name, the command changes to directory name in the same way as cd would have; pushd uses the cdpath directory list to resolve name and succeeds or fails in the same cases as cd. The pathname of the current directory is saved in a directory stack prior to the change. The directory stack is an implicit array variable maintained by the shell (which you cannot access directly), and each pushd adds the current directory to the left and pushes all existing entries to the right. The top (or first) element is always your current directory, and subsequent entries are the pathnames of your previous directories in reverse order. The popd command discards the top stack entry and changes to the new top entry, reducing the total number of items on the stack by one.
Use the form pushd +n to perform a circular shift of the directory stack by n positions, changing to the new top directory. A circular shift treats the list of elements as if they were in a ring, with the first preceded by the last and the last followed by the first. The shift changes your position in the ring without deleting any of the elements. Consider the following example:
% dirs /home/john /home/mary /home/doggie /home/witherspoon % pushd +2 /home/doggie % dirs /home/doggie /home/witherspoon /home/john /home/mary
Note that both before and after the pushd, /home/john precedes /home/mary, and /home/doggie precedes /home/witherspoon. The example also shows that, for the purpose of the pushd +n command form, /home/witherspoon (the last entry) is effectively followed by /home/john (the first entry).
Returning to a Previous Directory by Using the Directory Stack: popd After you have saved directories on the directory stack with pushd, you can use popd to return to a previous directory. The syntax for the popd command follows:
popd [ +n ]
Used in the form popd +n, the command deletes the nth entry in the stack. Stack entries are numbered from 0, which is your current directory. The following example shows the use of pushd, dirs, and popd together:
% pwd /usr/home/john % pushd /usr/spool % pushd uucppublic % pushd receive % dirs /usr/spool/uucppublic/receive /usr/spool/uucppublic /usr/spool _/usr/home/john % popd /usr/spool/uucppublic % dirs /usr/spool/uucppublic /usr/spool /usr/home/john % popd +1 /usr/spool/uucppublic /usr/home/john % popd /usr/home/john % dirs /usr/home/john
The C shell provides a number of commands for changing the active shell. Although your logon shell may be the C shell, you are not limited to it; you can change your shell to the Bourne shell or the Korn shell at any time by using the exec command. The exit and logout commands also change the active shell by returning you to the shell that was active before your current shell. When you issue these commands from your logon shell, they return you to the logon screen, which is itself a kind of shell (of somewhat limited functionality).
Other commands, such as umask and nohup, change the manner in which UNIX treats the shell.
Invoking a New Process: exec The exec command transfers control to the specified command, replacing the current shell. The command you specify becomes your new current shell. The syntax of the exec command follows:
exec command
Control cannot be returned to the invoking environment, because it is replaced by the new environment. Shell variables exported with the setenv command are passed to the new shell in the usual manner; all other command contexts, including local variables and aliases, are lost.
The exec command is used mainly in C shell scripts. The normal C shell behavior for executing commands that are C shell scripts uses two child processes: one process is a new C shell to interpret the script, and the other process is command(s) being executed. The exec command causes the C shell to eliminate one of the processes by having the C shell process replaced by the command process. exec most often is used if a script is used to set up an execution environment for a command (to set environment variables and check arguments, for example) and then run the command.
The exec command is equivalent to the Bourne shell exec.
Exiting from the Current Shell: exit The exit command causes the current shell invocation to be exited. Its syntax follows:
exit [ (exitExpression) ]
If the exit command is issued from within a shell script, the shell script is terminated, and control returns to the invoking shell. If exit is issued from your logon shell, the .logout script in your home directory is executed before the shell exits. Normally, the UNIX operating system redisplays a logon screen after an exit from the logon shell.
If you provide the optional exitExpression argument (which must be enclosed in parentheses), the argument is evaluated as an arithmetic expression, and the resulting value is used as the shell's exit code; otherwise, the current value of the status variable is taken as the shell's exit code. The status variable is described in "Using Predefined Variables," later in this chapter.
You can use the login command to log out from your current shell and to immediately log on under the same or a different User ID. Its syntax follows:
login name [ arg ... ]
Using this built-in shell command is not quite equivalent to logging out in the normal manner and then logging on. If you use the login command from a remote terminal, the line connection is not dropped, whereas logging out in the normal manner drops the line and requires you to reestablish the connection before you can log on again.
You cannot execute the login built-in command from a subshell; it is legal only for your logon shell.
For name, specify the user name with which you want to log on. Any arguments you specify after name are passed to the /bin/login command and are defined by /bin/login--not by the shell.
Exiting from a Logon Shell: logout You can use the logout command to log out from your logon shell:
logout
You also can terminate the logon shell (or any subshell) with the exit command. If you have the ignoreeof option set, you cannot use the EOF key (usually, Ctrl-D) to exit from the shell; in such a case, use logout or exit. See "Using Predefined Variables," later in this chapter, for a definition of the ignoreeof option.
Preventing a Command from Terminating Execution After Logout: nohup You can use the nohup command to run a command that is insensitive to the hang-up signal:
nohup [ command ]
The UNIX operating system always sends a hang-up signal (signal 1) to a process when its process group leader logs out. The net effect is that, generally, any command you are running when you log out is terminated. (Although you can't ordinarily issue the logout or exit command or enter an EOF character while you are running a command, you always can force a logout by turning off your terminal; or, if you are using a remote terminal connection, you can hang up the line.)
When you invoke command with nohup, the shell effectively disables the hang-up signal so that command cannot receive it, which enables command to continue to execute after you log out. Use nohup command to run command with the hang-up signal disabled.
You can disable the hang-up signal for your interactive shell or from within a shell script by using the trap built-in command. Programs written in the C or C++ languages also can disable or ignore the hang-up signal. Not all commands are able to ignore a hang-up signal, however. If you use nohup to invoke the command, you are assured that the hang-up signal will be ignored regardless of whether the command disables the signal.
Use nohup with no arguments from within a shell script to disable the hang-up signal for the duration of the script. A job placed in the background (see "Executing Jobs in the Background: &," later in this chapter) using the & operator has nohup automatically applied to it.
The file-creation mask (commonly called the umask) is an attribute of the shell process, just like the current directory is an attribute. The file-creation mask specifies the default permissions assigned to new files you create. When redirecting the output of a command to a file with the > operator, for example, it would be extremely inconvenient if the system prompted you for file permissions every time it created a file. Prompting would be especially annoying because, most of the time, you would assign the same permissions to all new files.
If you're not familiar with file permissions, you might want to review Chapter 4, "The UNIX File System." Briefly, file permissions indicate who may read, write, or execute the file.
The file-creation mask is a device you use to indicate what permissions UNIX is to assign to a new file by default. If you want some other access permissions for a file, the usual approach is to first create the file and then change the file's permissions with the chmod command.
The file-creation mask itself is a binary value consisting of nine bits; each bit corresponds to the permission bits for a file. As a matter of convention, the nine bits are represented by three octal digits; each digit represents three bits. Using octal number representation for the file-creation mask is a matter of convention, not necessity, yet the umask command does not enable you to use any other number form for displaying or setting the file-creation mask. You must use octal to set the mask, and you must interpret octal values to understand the mask when displayed.
As for the mask itself, each of the bits in the mask indicate whether the corresponding bit of the file permission should be set to off, (set to zero). By default, virtually all UNIX commands attempt to set reasonable permission bits to 1 when creating a file. A command that creates a data file (such as a text file) tries to create the file with permissions of 666. In octal, this grants read and write permissions to you (the file's owner), to other members of your UNIX group, and to all other system users; however, it leaves the Execute permission unset. Commands that create executable files (such as cc and ld) attempt to set the file's permissions to 777, which, in octal, set the Read, Write, and Execute bits for all users.
Because of this default action by UNIX commands, it is the function of the file-creation mask to specify permissions you don't want set. When you set a bit in the file-creation mask, it causes the corresponding bit of the file's permissions to be forced to 0. Bits not set in the file-creation mask are interpreted as don't care: the file-permission bit remains unchanged.
The bits of the file permissions are written as rwxrwxrwx. The first three bits represent Read, Write, and Execute permissions for the file's owner; the second set of three bits represents Read, Write, and Execute permissions for the file's group; and the third set of three bits specifies the permissions for other users. To grant Read and Write permissions to the file's owner but only Read access to other users, the appropriate file-permission setting is the bits 110100100. Writing this in octal, you arrive at the familiar permissions value of 644, which you already may have seen in the output of the ls command.
Remember that UNIX commands try to create files with all reasonable permissions set. For a data file, these bits are 110110110, corresponding to rw-rw-rw-. To get the permissions switched to rw-r--r--, you need to set off the fifth and eighth bits. A file-creation mask of 000010010 (in octal 022) would do the trick. When the file is created, UNIX lines up the bits in the file permissions requested by the command and your file-creation mask like this:
1 1 0 1 1 0 1 1 0 attempted file permissions 0 0 0 0 1 0 0 1 0 file creation mask ---------------- 1 1 0 1 0 0 1 0 0 actual file permissions
What you have to do when using the umask command, therefore, is to first decide what file permissions you want to assign to your new files by default and then write a bit mask as an octal number that sets the appropriate file-permission bits to 0.
As it happens, most UNIX users want to reserve Write permission for their files to themselves, but they are willing to let other people look at the files. The appropriate file-creation mask for this is 022 in octal. In many cases, the system administrator sets up the system so that the umask 022 command is executed for you when you log on. If the administrator has not set up a default, or you want to use another file-creation mask, you can set a new mask in your logon profile.
The actual syntax of the umask command is straightforward. To display the current process file-creation mask, use the umask command like this:
% umask 022
You also can use umask to set the process file-creation mask by specifying the octal argument:
% umask octal
The process file-creation mask is set to the bit pattern corresponding to the low-order three bits of each digit in the octal number octal.
C shell provides two commands for echoing arguments to standard output: echo and glob. The only difference between them is the delimiter used to separate words in the output line.
The echo command, although most often used when writing shell scripts, also comes in handy in a number of keyboard situations--for example, when constructing a pipe to a non-interactive command (echo arg1 | command). One of the best examples of the echo command is using it to display the value of a shell variable:
% echo $path /usr/bin /bin /usr/local/bin /users/chen/bin
In this case, the variable substitution expression $path does the real work; the echo command provides only the step of printing the value on the terminal. Nonetheless, without the echo command, it would be cumbersome to check the value of a variable. The set command not only prints a single variable, but set can be used to print all variables. Using set to print all shell variables can produce a lengthy list that takes time to search through for the entry you want.
The glob command, on the other hand, rarely is used in any context. Originally, it was intended to be called from a C program (not a shell script) to get the shell to expand a filename wildcard expression. Most C programmers don't use this technique, though, because it relies on the existence of the C shell.
Using the echo Command The echo command prints a line containing its arguments to standard output. The syntax for the command follows:
echo [ -n ] wordlist
The arguments are printed with one intervening blank between them and a newline character after the last one. The echo command does not modify the words in wordlist in any way, but the arguments as seen by echo might differ from those on the original command because of variable, command, and history replacement and filename globbing. For example, the command
echo Directory $cwd contains these files: *.cc
might generate the following line to standard output:
Directory /usr/lib1 contains these files: myprog.cc bigprog.cc
Specify option -n to suppress printing a newline character; this enables the next input or output to occur on the same line as the output of the echo command.
Using the glob Command The glob command also prints a line containing its arguments to standard output. The syntax for the command follows:
glob [ wordlist ]
Use glob to print the words in wordlist to standard output. The words are printed with a null character between each (not white space, as with echo). The last word in wordlist is not followed by a newline character.
The words in wordlist are subject to variable, command, and history substitution and filename expansion in the usual manner. After scanning for substitutions, the resulting strings are redivided into words, which then are written using the null character delimiter.
The glob command is similar to echo and differs only in the delimiter used to separate words in the output line. Because most terminals cannot print a null character, glob generally is not used to generate terminal output. It is intended to be called from a C language program, in the form
system("/bin/csh -c 'glob *.doc'");
to invoke the shell substitution and filename-expansion mechanisms.
TIP: The C shell provides no direct means of logging messages to standard error. The lack of direct support from the C shell to log specifically to standard error can be very problematic when writing scripts--especially scripts intended to be part of a pipeline (e.g., command1 | yourScript | command2) or otherwise have the script's output redirected in some fashion (e.g., yourScript > outputFile). Error messages not placed on the standard error will be redirected, while error messages placed on the standard error will be seen unless the user specifically redirects the standard error. In short, placing a message on standard error ensures that the user will see the message. The following code shows an alias named stderr that places a message on the standard error. It is a bit cumbersome because it requires three extra processes to accomplish the task, but this should not be an issue because logging to standard error is infrequent and occurs only in error situations.
The alias saves a process over using a script file but suffers from two drawbacks. It does not accept input from standard input (cat errFile | stderr), and the alias does not permit redirection on the same command line (stderr message > errFile). The following script file, at the expense of an extra process, provides command-line redirection and handles input from standard input or command-line arguments:
eval [arg ... ]
You can use eval to rescan the arguments arg for variable, command, and history substitutions; filename expansion; and quote removal;, and then execute the resulting words as a command. For example, if eval were passed the argument 'ls foo*' and the files foo.txt and foo.doc matched the pattern foo*, eval would expand the foo* expression and then execute the following command:
ls foo.txt foo.doc
With eval, you essentially can write shell script lines with a shell script and execute the resulting generated commands. Remember that to embed variable symbols in a string, however, you must hide the leading dollar sign from earlier shell substitutions.
eval is useful when used with commands that generate commands, such as resize or tset. For example, resize generates a series of setenv commands. Without eval, using resize is a three-step task:
resize > /tmp/out; source /tmp/out; rm /tmp/out
With eval, using resize is considerably simpler:
eval ´´resize´´
The eval command implemented by the C shell is equivalent to the Bourne shell eval command.
The newgrp command is the same as the UNIX newgrp command:
newgrp groupname
Although issued from your logon shell (not to be confused with a logon shell script--the logon shell is simply the shell started up for you when you log on), newgrp causes the current shell to be replaced by a new shell with the real and effective Group IDs both changed to the specified group groupname. Because the shell is replaced, all context, including exported variables and aliases, is lost.
Use the newgrp command when you have been authorized by the system administrator for membership in two or more user groups, and you want to change your Group ID from your current or logon group to another group. Your Group ID is used by the system when determining whether to grant you access to files.
You can use time with no argument to display the amount of CPU time in seconds used by the current shell and all commands and subshells invoked since its start. This form of the command is usually of interest only to folks who are being billed for the amount of machine time they use, as might be the case if you are renting time on a commercial machine. By occasionally entering the command with no arguments, you can monitor how much machine time you have used and limit your online time accordingly.
time [ command ]
Only for your logon shell will this be the amount of machine time used since you logged on. Also, note that the time reported is not elapsed wall-clock time--it is only the machine (or CPU) time used.
Use the form time command to execute command and report the amount of CPU time used by the command's execution. The command must be a simple command--not a compound command, statement group, or parenthesized statement--and cannot be a pipeline.
You might be interested in timing the execution of a command if you are a production operations manager and you want to find out how much time a new application is adding to your daily workload. A development programmer would use the time command to determine whether a new program has a performance problem. The average interactive user, however, would have infrequent occasion to use the time command.
One of the handier features of the C shell is the alias feature. An alias is a shorthand method of referring to a command or part of a command. If you have several favorite options that you always supply to the ls command, for example, instead of having to type the whole command every time, you can create a two-character alias. Then you can type the two-character alias, and the shell executes the alias definition. In addition to providing shortcuts, aliases are a convenient way of handling common typos. I often type mroe for more or jbos for jobs, for example. Setting up aliases for mroe and jbos therefore saves me time, because I don't have to retype those commands.
An alias can represent not only a command name, but also leading options and arguments of the command line. Any words you type following the alias name are considered to follow options and arguments included in the alias definition, enabling you to customize the command with key options and arguments.
You can achieve more complex processing by using shell scripts, where the function performed by the shell script file's name used as a command can be arbitrarily complex. The command alias feature was provided only for use as a keyboard shortcut, and anything that can be achieved by using an alias can be done with shell scripts.
You should add command aliases you use often to your .login file, so that the alias is defined every time you log on. It is often handy, however, to define command aliases at the keyboard for special commands you'll be using during your current session. If you don't incorporate the alias into your .login file, it is lost when you log out.
The alias command enables you to list currently defined aliases, to define a new command alias, or to change an existing alias. The command format follows:
alias [ name [ definition ... ]]
For name, choose a word consisting of upper- and lowercase letters and digits. For definition, write any sequence of words that defines the command string for which you want name to stand. The following defines two aliases for the rlogin command, each providing a different host. It's shorter to type the alias name for the destination host than it is to type the rlogin command and options.
alias druid rlogin druid -l root alias ducati rlogin ducati.moto.com
If you want to change the definition of an alias, just define the alias again.
After you define aliases, you can display a list of their names and definitions by entering the alias command without arguments, as in this example:
% alias druid (rlogin druid -l root) ducati (rlogin ducati.moto.com)
You also can display the definition of a specific alias by specifying its name as an argument:
% alias druid rlogin druid -l root
Alias substitution occurs early in the shell's processing cycle for commands, thereby enabling you to use globbing (filename replacement), variable substitution, command substitution, and command-history substitution in the wordlist. You therefore often will need to quote at least one of the words of definition and perhaps the entire alias definition. Some people always enclose the alias definition in quotes to avoid surprises. Consider the following alias:
alias lc ls *.{cc,hh}
For a C++ language programmer, the alias would be rather natural: Simply by typing lc, you get a listing of all source program files in the current directory, devoid of any other file clutter.
NOTE: Note that substitutions occur when the alias command is processed unless you quote all or part of the wordlist.
The preceding alias definition does not work as expected, however. The filename pattern *.{cc,hh} is substituted on the alias command itself, and the actual alias stored (depending on the actual directory contents when you enter the alias command) follows:
% alias lc ls CIM_EnvImp.cc CIM_Util.hh EventManager.cc LogInstances.cc
Because the filename pattern is replaced before the alias definition is stored by the shell, the lc alias doesn't list all files ending in .cc or .hh. It attempts to list the files CIM_EnvImp.cc, CIM_Util.hh, EventManager.cc, and LogInstances.cc, whether or not they exist in the current directory.
The alias should have been defined as this:
% alias lc ls '*.{cc,hh}'
An alias definition also can use command aliases. During alias substitution, the alias definition is scanned repeatedly until no further substitutions can be made. An alias definition for name, however, cannot invoke the name alias within itself; a reference to name in the definition is taken as a reference to the built-in shell command or executable file name, not as a reference to the alias. This enables you to use an alias to redefine a system command or a built-in shell command. For example,
% alias pg pg -cns -p"Page %d:"
You can refer to arguments of the original command line--before any substitutions are made--by using the command-history substitution syntax (see "Command History," later in this chapter). For example, the command
alias print 'pr \!* | lp'
defines an alias named print that executes the pr command using all the arguments of the original command line (\!*) and then pipes the output to lp for printing.
To properly understand and use the alias command, you must be clear about the way an alias is used. When you define an alias by entering the alias command, the only thing that happens at that time is that the system stores the alias in computer memory. Later, when you enter a command with the same name as the alias, the C shell does a little magic. The command you typed is not executed in the form in which you typed it. Instead, the command name (which is an alias name) is replaced by the value of the alias. The result is a new command text--the first part is the alias definition, and the rest consists of any other arguments you typed.
Suppose that you define an alias for the ls command as this:
% alias lax ls -ax
If you later enter the command
% lax big*.txt
the command actually executed is
ls -ax big*.txt
The command alias (lax) is replaced by its definition (ls -ax). Remaining arguments on the command line (big*.txt) simply are tacked on after the alias substitution to yield the command the computer actually executes.
Using history substitutions (for example, !*, !^, !:2 ...) in an alias provides additional flexibility by enabling the executed command to use arguments in a different order or a different form than entered; this requires a little extra work from the shell. Consider the following alias definition:
alias lsp 'ls \!* | lp'
Entering the command lsp *.cc *.csh results in alias substitution for lsp. The symbol !* causes the arguments you entered on the line *.cc *.csh to be inserted into the alias definition instead of being tacked on after the alias definition. In other words, if an alias definition contains a history substitution, the shell suspends its normal action of tacking on command arguments after the alias value. The command actually executed is ls *.cc *.csh | lp. Without this special mechanism, the executed command would have been ls | lp *.cc *.csh, with the final *.cc *.csh tacked on in the usual manner. This would lead to an undesirable result: Instead of printing a directory listing, the lp command would print the full contents of the files.
When writing an alias, you therefore need to visualize what will happen when the alias is substituted in later commands.
You can use unalias to delete one or more aliases. You can delete a specific alias by specifying its name as an argument, or you can delete multiple aliases by using pattern-matching:
unalias name unalias pattern
If you specify a specific alias name, only that alias definition is deleted. If you specify a pattern, all those currently defined aliases whose names match the pattern are deleted. pattern can contain the pattern-matching characters *, ?, and [...]. In the following example, the first line deletes the lx alias, and the second line deletes all currently defined aliases:
unalias lx unalias *
The C shell command-line options provide a convenient way of modifying the behavior of a C shell script to suit your needs. Options can be specified on a command line, such as this:
% csh -f
Or, if your UNIX version supports the #! notation, you can specify an alias on the first line of a script, such as this:
#!/bin/csh -f echo *
If an option is needed temporarily, the command line is the best place to supply the option. If the option is needed permanently, place it on the #! line.
Unless one of the -c, -i, -s, or -t options is set, the C shell assumes that the first argument on the command line is the command to be executed and that each additional argument is intended for the command being executed. For example, the command
% csh command arg1 arg2 arg3
causes the C shell to execute command with three arguments (arg1, arg2, arg3), which will be assigned to the argv array variable. When the -i, -s, or -t option is set, the shell assigns all arguments, including the first to the argv array variable. The -c option allows only one command-line argument and takes it as a list of commands to be executed; after execution of the argument string, csh exits.
Command-line options are used by the C shell itself--not by the command to be executed. Command-line options are indicated with a dash (-) followed by this option: csh -v. If multiple options are needed, the options may be preceded by only one dash (csh -fv) or by using one dash per option (csh -f -v). Mixing option-specification methods is allowed (csh -f -vx). The following command shows the mixing of command-line options with normal command execution:
% csh -fv command arg1 arg2 arg3
Table 12.4 provides a summary of C shell command-line options.
| Option | Name | Description |
| -b | Break | Delimits a break in command-line option processing between arguments intended for the C shell and arguments intended for a C shell script. All command options before -b are interpreted as C shell arguments, and all command options after -b are passed on to the C shell script. Note: The -b option is not available on all UNIX platforms. |
| -c commandString | Commands | Executes commands from the commandString parameter that immediately follows the -c option. The commands in commandString may be delimited by newlines or semicolons. All command-line arguments after -c are placed in the argv variable. The -c option is used when calling the C shell from a C or C++ program. -c is the only option that requires a parameter. |
| -e | Exit | Exits the current shell if any command returns a nonzero exit status or otherwise terminates abnormally. Setting this option is easier than checking the return status of each command executed. |
| -f | Fast | Uses fast-start execution. The C shell does not execute the .cshrc or .login file, which speeds up the execution of a C shell script. This is a good optimization if a C shell script does not need any of the variables or aliases set up in the initialization files. |
| -i | Interactive | Forces interactive-mode processing. If shell input does not appear to be from a terminal, command-line prompts are not issued. |
| -n | Not | Parses shell syntax but does not execute commands. The -n option is useful for debugging shell syntax without actually having to execute resultant commands after all shell substitutions are made (for example, aliases, variables, and so on). |
| -s | Standard | Reads command input from standard input. All command-line arguments after -s are placed in the argv variable. Using -s can prevent unnecessary temporary files by piping output of commands directly into the shell (genCshCmds | csh -s). |
| -t | execuTe | Reads and executes a single line of input. You can use the backslash (\)to escape the newline to continue the input on the next line. |
| -v | Verbose | Sets the predefined verbose variable. When verbose is set, all commands are echoed to standard output after history substitutions are made but before other substitutions are made. -v is useful for debugging C shell scripts. |
| -V | Very | Sets the predefined verbose variable before the .cshrc is executed. |
| -x | eXecution | Sets the predefined echo variable. Commands are echoed to standard output right before execution but after all substitutions are made. |
| -X | eXtra | Performs extra command echoes. The -X option sets the predefined echo variable before .cshrc is executed. |
The shell supports additional options that you can switch on or off during shell operation. These options are controlled by variables; if the variable is set, the corresponding option is activated; if it is not, the option is off. These options are described in "Using Predefined Variables," later in this chapter. Their names are echo, ignoreeof, noclobber, noglob, nonomatch, notify, and verbose.
Additionally, the