The C-Shell
One of the first “new” shells to emerge was the csh or C-Shell. It is so
named because much of the syntax it uses is very similar to the C programming
language. This isn’t to say that this shell
is only for C programmers, or programmers in general. Rather, knowing C makes learning the
syntax much easier. However, it isn’t essential. (Note: The csh syntax is similar to C,
so don’t get your dander up if it’s not exactly the same.)
The csh is normally the shell that users get on many UNIX
systems. Every place I ever got a UNIX
account,
it was automatically assumed that I wanted csh
as my shell.
When I first started out with UNIX,
that was true. In fact, this is
true for most users. Because they don’t know any other shells, the csh is a good
place to start. You might actually have tcsh on your system, but the principles
are the same as for csh.
As you login
with csh as your shell, the system first looks in the global
file /etc/cshrc. Here, the system administrator
can define variables or actions
that should be taken by every csh user. Next, the system reads two files in your
home directory: .login and .cshrc. The .login file normally contains the
variables you want to set and the actions you want to occur each time you log
in.
In both of these files, setting variables have a syntax that is unique to
the csh. This is one major difference between the csh and
other shells. It is also a reason why it is not a good idea to give root csh
as its default shell.
The syntax for csh is
set variable_name=value
whereas for the other two, it is simply
variable=value
Because many of the system commands are Bourne scripts, executing them with
csh ends up giving you a lot of syntax errors.
Once the system has processed your .login file, your .cshrc is processed.
The .cshrc contains things that you want executed or configured every time you
start a csh. At first, I wasn’t clear with this concept. If you are logging in
with the csh, don’t you want to start a csh? Well, yes. However, the reverse is
not true. Every time I start a csh, I don’t want the system to behave as if I
were logging in.
Let’s take a look as this for a minute. One of the variables that gets set
for you is the SHELL variable. This is the shell
you use anytime you do a
shell escape from a program. A shell
escape is starting a shell as a subprocess of a program. An example of a program that allows a shell escape is vi.
When you do a shell
escape, the system starts a shell as a new (child)
process of whatever program you are running at the time. As we talked about
earlier, once this shell
exits, you are back to the original program. Because
there is no default, the variable
must be set to a shell.
If the variable is set to something else, you end up with an error message
like the following from vi:
invalid SHELL value: <something_else>
where <something_else> is whatever your SHELL variable
is defined as.
If you are running csh and your SHELL variable
is set to /bin/csh, every
time you do a shell
escape, the shell you get is csh. If you have a .cshrc file
in your home directory,
not only is this started when you log in, but
anytime you start a new csh. This can be useful if you want to
access personal aliases from inside of subshells.
One advantage that the csh offered over the Bourne Shell is its ability to
repeat, and even edit, previous commands. Newer shells also have this ability,
but the mechanism is slightly different. Commands are stored in a shell
“history list,” which, by default, contains the last 20 commands. This is normally
defined in your .cshrc file, or you can define them from the command line.
The command set
history=100
would change the size of your history list to 100.
However, keep in mind that everything you type at the command line
is saved in the history file. Even if you mistype something, the shell
tosses it into the
history file.
What good is the history file? Well, the first thing is that by simply
typing “history” with nothing else you get to see the contents of your history
file. That way, if you can’t remember the exact syntax of a command you typed
five minutes ago, you can check your history file.
This is a nice trick, but it goes far beyond that. Each time you issue a
command from the csh prompt, the system increments an internal counter that
tells the shell
how many commands have been input up to that point. By default,
the csh often has the prompt set to be a number followed by a {3f0b0cf5c640d99e599990c4a720721a04ec3a009b1323dd81fc335ceb655a63}. That number is
the current command, which you can use to repeat those previous commands. This
is done with an exclamation mark (!), followed by the command number as it
appears in the shell
history.
For example, if the last part of your shell
history looked like this:
21 date
22 vi letter.john
23 ps
24 who
You could edit letter.john again by simply typing in !22. This repeats the
command vi letter.john and adds this command to your history file. After you
finish editing the file, this portion of the history file would look like
21 date
22 vi letter.john
23 ps
24 who
25 vi letter.john
Another neat trick that’s built into this history mechanism is the ability to
repeat commands without using the numbers. If you know that sometime within your
history you edited a file using vi, you could edit it again by simply typing
!vi. This searches backward though the history file until it finds the last time
you used vi. If there were no other commands since the last time you used vi,
you could also Enter !v.
To redo the last command you entered, you could do so simply by typing in
!!.
This history mechanism can also be used to edit previously issued
commands. Lets say that instead of typing vi letter.john, we had typed in
vi letter.jonh. Maybe we know someone named jonh, but that’s not who we meant to
address this letter to. So, rather than typing in the whole command, we can edit
it. The command we would issue would be !!:s/nh/hn/.
At first, this seems a little confusing. The first part, however, should be
clear. The “!!” tells the system to repeat the previous command. The colon (:)
tells the shell
to expect some editing commands. The “s/nh/hn/” says to
substitute for pattern nh the hn. (If you are familiar with vi or sed, you
understand this. If not, we get into this syntax in the
section on regular expressions and metacharacters.)
What would happen if we had edited a letter to john, done some other work
and decided we wanted to edit a letter to chris instead. We could simply type
!22:s/john/chris/. Granted, this is actually more keystrokes than if we had
typed everything over again. However, you hopefully see the potential for this.
Check out the csh man-page
for many different tricks for editing previous
commands.
In the default .cshrc are two aliases that I found quite useful. These are
pushd and popd. These aliases are used to maintain a directory “stack”. When you
run pushd <dir_name>, your current directory is pushed onto (added to) the
stack and you change the directory to <dir_name>. When you use popd, it
pops (removes) the top of the directory stack
and you change directories to it.
Like other kinds of stacks, this directory stack
can be several layers deep. For example, lets say that we are currently in our
home directory.
A “pushd /bin” makes our current directory /bin with our home directory
the top of the stack. A “pushd /etc” brings us to /etc. We do it one more time with pushd
/usr/bin, and now we are in /usr/bin. The directory /usr/bin is now the top of the stack.
If we run popd (no argument), /usr/bin is popped from the stack
and /etc is
our new directory. Another popd, and /bin is popped, and we are now in /bin. One
more pop brings me back to the home directory.
(In all honesty, I have never used this to do anything more than to switch directories, then jump back to where I was. Even that is a neat trick.)
There is another useful trick built into the csh for changing directories.
This is the concept of a directory path. Like the execution search path,
the
directory path is a set of values that are searched for matches. Rather than
searching for commands to execute, the directory path is searched for
directories to change into.
The way this works is by setting the cdpath variable. This is done like any
other variable in csh. For example, if, as system administrator,
we wanted to
check up on the various spool directories, we could define cdpath like this:
set cdpath = /usr/spool
Then, we could enter
cd lp
If the shell
can’t find a subdirectory
named lp, it looks in the cdpath
variable. Because it is defined as /usr/spool and there is a /usr/spool/lp
directory, we jump into /usr/spool/lp. From there, if we type
cd mail
we jump to /usr/spool/mail. We can also set this to be several directories,
like this:
set cdpath = ( /usr/spool /usr/lib /etc )
In doing so, each of the three named directories will be searched.
The csh can also make guesses about where you might want to change
directories. This is accomplished through the cdspell variable.
This is a
Boolean variable
(true/false) that is set simply by typing
set cdspell
When set, the cdspell variable
tells the csh that it should try to guess
what is really meant when we misspell a directory name.
For example, if we typed
cd /sur/bin (instead of /usr/bin)
the cdspell mechanism attempts to figure out what the correct spelling is.
You are then prompted with the name that it guessed as being correct. By typing
in anything other than “n” or “N,” you are changing into this directory. There
are limitations, however. Once it finds what it thinks is a match, it doesn’t
search any further.
For example, we have three directories, “a,” “b,” and “c.” If we type “cd
d,” any of the three could be the one we want. The shell
will make a guess and
choose one, which may or may not be correct.
Note that you may not have the C-Shell on your system. Instead, you might
have something called tcsh. The primary difference is that tcsh does command
line completion and command line
editing.