Unix Lab



Shell Issues



Working with the C Shell

We mentioned earlier that Unix has a kernel layer that "talks" to the hardware and a shell layer that acts as an intermediary between the user and the kernel. There are at least three different Unix shells that are used. The one that you get by default when you use a Unix system is determined by the installation. Here we will look at the "C shell" which is the default within the Computer Science Department at SJSU.

Metacharacters

Metacharacters are sometimes called "wildcard" characters. Metacharacters are recognized by the shell. These characters can allow you to specify a group of files at one time, for example. When used with certain Unix commands, they allow you to select just the files to which you want to apply the command without having to re-issue the command over and over on each individual file.

Create a subdirectory under your home directory in which you will place certain files for this module. Go to that directory and issue the command:

cp /handouts/cs46blab/* .

We have already seen that the '.' character stands for "this directory". The first part of the copy command is a filename but the '*' character is not part of the filename.

Instead, this is a metacharacter. We'll see more about metacharacters in the context of regular expressions in another module. When used as part of a filename, Unix takes the character to mean that any string of characters (zero or more) will match that character. In particular, since every filename in the directory from which you are copying files has a name consisting of characters, you will match every filename in that directory. That is, you will copy every file from that directory to your working directory. Check this by listing the files in your working directory.

In order to further examine the use of the '*' metacharacter, type the following command from your working directory containing the files you just copied:

ls -l *.txt

What do you see? Which files got left out of the listing?

Issue an ls command that will display the long listing for just the files with the characters "list" somewhere in the filename (hint: you can use '*' in more than one location).

The '?' is another metacharacter. The shell will try to match a single character in place of the metacharacter. For example, type:

ls -l Chap?.*

You can also use the "[...]" as metacharacters. The shell will match any single character within the square brackets. For example, type:

ls -l Chap[12].txt

Notice that there are no blanks or commas between the characters to be matched. How would you get a long listing for Chap2.txt and Chap3.txt but not Chap1.txt?

Suppose you wish to transfer to subdirectory "sub1" just under your home directory from a subdirectory deep in the tree hierarchy under your home directory. One choice is to issue the cd command with no parameters which will place you in your home directory and then to issue the command to take you to the sub1 subdirectory as in:

cd

cd sub1

An alternate choice is to use the '~' metacharacter by typing:

cd ~/sub1

The '~' metacharacter is interpreted by the shell to mean your home directory.

Although we have exhibited the use of metacharacters with just a few Unix commands, they can be used with many of the commands. For example, they can be used with the rm command. One should be careful with the use of metacharacters. For example, if you typed rm * you would delete all the files in the directory in which you were located. This might be what you want to do but beware!

One good piece of advice is to check which files you will actually affect with the use of metacharacters by using the same characters with the ls command.


aliases

The C shell has a feature that allows you to customize your computing environment by allowing you to rename or abbreviate the standard Unix commands.

Type the following command:

alias ls ls -l

and then follow it with the command:

ls .

Even though you did not use the -l option you still got the long listing. This is because the alias command set up an alias between the ls command and the ls command with the -l option. Think of it as the following: each time you enter ls as the command name, the shell will substitute the replacement text that you supplied in the alias command.

One very useful alias is the following:

alias rm rm -i

What is the -i option? (Use the man command to find out.) How will this be useful? Actually, you may already have this alias installed as a default on the system you are using. We'll see shortly how this is done.

Go to your home directory. If you issue the ls command with the -a option, you will see that there are a number of files that you normally don't see. Each of these files begins with the '.' character. These files are usually resource files that are used by various programs in the Unix environment.

One of these files is .cshrc and is the resource file read by the C shell when it first starts up. The file is just a text file and you can modify it to fit your needs. One of the ways you can use this file is place any aliases you wish to use all the time. Aliases that you enter on the command line as we did above will disappear when you logout from the system.

Here are some aliases you may wish to add to your .cshrc file. To add them, use your favorite editor to edit the .cshrc file. Place all the aliases together so that you can quickly locate them if you want to make changes. You probably already have a few there as a result of the default .cshrc file that you were given with your Unix account.

alias ls ls -F
The -F option will tell ls to place the '/' character after the names of any directories. This allows you to quickly distinguish between directories and files.

alias dir ls
Old habits die hard. If you are a DOS user who can't remember to use ls to view your directory, you can alias dir to the ls command. By the way, if you have already aliased the ls command to ls -F as above, then dir will also produce the same result as typing ls -F.

alias bye logout
You can probably come up with lots of these that customize your interaction with the Unix C shell. It's probably best to restrict yourself to a few of these aliases. Otherwise you may find yourself on a Unix system someday that doesn't support aliases and you won't remember any of the (un-aliased) Unix commands. Not all shells allow this feature.

alias cd 'cd \!* ; ls -F'
This one takes some explanation. The single quote character surrounding the string that is to replace cd is there to "protect" it from the shell. The '*' character is a metacharacter and the shell would ordinarily try to treat it in that way while it was executing the alias command. Instead, we want the metacharacter to be handled later after the cd string has been replace by the characters between the two single quote characters. The '\' character together with the '!' and the '*' characters will cause the parameters that you supply to the cd command (after it has been aliased) to be copied into this spot. The ';' character serves as a separator between Unix commands, allowing you to have two or more commands on a single line.

In the end, what you will have is that every time you issue the cd command, you will also get the ls -F command being issued to show you the files and directories in the directory to which you have changed.

Once you have entered the aliases into your .cshrc file, they will be available to you the next time you login. You can tell the C shell to read them now and make them available to you now by telling it to read the .cshrc file with the command:

source .cshrc

Once you have issued the source command, your aliases are now available to use immediately.


history

One of the other features of the C shell is something called history. At the command line type:

history

You should see a number of lines printed on your screen. They will be the previous commands that you entered.

The default number is 20 here in our department but that number can be reset to whatever you wish. (The number can be reset by inserting the following line into your .cshrc file
set history=nn
where nn is the number you wish.)

Having the ability to view past commands is of some interest but the nice feature is the ability to re-issue commands without having to retype them. Here is an example of what one might see after typing the history command.

    41  14:31   dir
    42  14:39   grep alias .cshrc
    43  14:58   history
    44  14:58   grep history .cshrc
    45  15:00   cd projectFolder
    46  15:00   cd patternFolder
    47  15:01   cp PatternMaker.java PatternMaker.java.save
    48  15:01   vi PatternMaker.java
    49  15:02   javac -deprecation PatternMaker.java
    50  15:02   vi PatternMaker.java
    51  15:03   javac -deprecation PatternMaker.java
    52  15:03   java PatternMaker 126 10000
    53  15:03   ps
    54  15:04   kill 3821
    55  15:04   ps
    56  15:05   rm PatternMaker.java.save
    57  16:57   cd
    58  16:58   grep history .cshrc
    59  17:01   history
    60  17:01   history > temp

The shell keeps a counter for the commands you have entered since you logged into the system. In this case the last command that was typed was the 60th since logging on. The most recent 20 commands are shown. The second column shows the time of day when the command was issued. The remaining information on each line is the actual command that was executed.

Use the results from the history command you typed earlier. Here we will refer to the history record shown above but yours will, of course, be different. Type the following command (instead of the number 58, use an appropriate number for your history record):

!58

What do you see? What has happened?

Issue three different ls commands. For example, you could issue some of the ls commands used earlier in the exercise using metacharacters.

Now type the command:

!ls

What do you see? Which of the previous ls commands was issued?

The character '!' tells the C shell to search the history record working backward from the most recent command. If you specify a number, then it will execute that command. If you specify a character string following the '!' character, then it will look for a command that begins with those characters. If we look at command number 49 above, we can see that if we were making some changes to the source file and then re-compiling, that it would be easier to type:

!49

or

!javac

rather than having to re-type the entire command.

You have to be aware that the shell's history mechanism merely re-issues the command that you had issued earlier. It may not make sense to re-issue that command if things have changed. For example, if you re-issue a javac command but are no longer in the directory containing the source file, then javac will report that it could not find the source file.


Processes

Unix is a multitasking operating system. This means that that it can have multiple tasks running simultaneously. A Unix task is usually called a process. There is also a special type of Unix process called a thread, which you will study in advanced coursework. In this lab, we will identify a task with a process. You have been running at least two processes at different times in this lab. One is associated with the window in which you are viewing this "lab manual". That process is running Netscape or some other browser. Another is any Unix command that you run in a separate window.

Actually, since there is probably only one central processing unit in the machine you are using (some Unix machines, like the file server in DH450, have multiple CPUs each capable of running separate processes simultaneously), there can really only be one process running at a time. Unix is capable of switching between processes quickly. If you are browsing the network, for example, then in the time that it takes a file to download from some other site on the network, you can go back to the window in which you issue Unix commands and ask for a listing or directory change. The browser task is still being given time as it needs it and the Unix command is being carried out as Unix rapidly switches between the two tasks.

The situation is even more complicated on the Sun workstations in the department since Unix is also a multi-user operating system. It can handle multiple users at the same time. Actually, this is just an extension of the multitasking concept.

Type the following command:

ps

This is the process status command. You will see displayed on the screen a table containing 5 columns. Each line in the table corresponds to a process that Unix is running on your behalf. Some of these may be related to the windows environment, some of these may be related to the process you have running the browser, etc. The PID column is the process ID for each process. This is a number assigned by the Unix system that uniquely identifies the process.

The TT and STAT columns have to do with the terminal to which the process is attached and the status of the process (e.g. IW = idle and waiting).

The TIME column gives you the amount of CPU time that has been consumed by that process so far and the COMMAND column gives you the command itself that is being executed by that process (e.g. -csh = C shell process).

Unix has the ability to run a process in a "background" mode. This means you can issue a command and gain access to the terminal immediately so you can issue another command. This is useful if you have some process that is going to take a long time and you want to work on something else while Unix executes the command. All you have to do is place the '&' character at the end of the command.

Copy the file Patterns.java and PatternMaker.java from /handouts/cs46blab (if you don't already have a copy from an earlier module). Now type the command:

javac Patterns.java

followed by:

java Patterns 126 10000 > temp &

Now immediately type the command:

ps

How can you tell if java was operating in the background? What message, if any, did you get to tell you that the java task was completed?

There is a way of placing an active process into the background and suspending it. This will halt its execution temporarily but won't kill the task.

Remove the file named temp that you created in the previous exercise. Then issue the command:

java Patterns 126 100000 > temp

Now type:

^Z

(That's an upper case Z while you hold down the control key.) What do you see? Check out if the process is still in the system using ps. What do you see? Has the java process accumulated any CPU time? How much? Wait a few more seconds and type ps again. Does it appear that the java process is executing in the background?

Now type:

fg

This puts the process that you formerly suspended into the foreground. After a few more seconds, suspend the process again (how?) and use ps to have a look to see what is happening. Has forever accumulated any more time? How much more?

Suspend the java process again (if it has completed then remove the temp file and start it again first).

Issue the ps command again and note the PID number (Process ID) for the java process. What is the PID for the java process?

Now we want to simply kill the process before it takes up any more CPU time. To do this type (instead of 4333, use the correct PID for your process):

kill 4333

Now use ps to see if the java process is still active. What message do you see to indicate otherwise?

Sometimes using kill is the only way to get out of a process that is stuck in an infinite loop.


Click on to go back to the main directory.

Click on to take the quiz for this module.

These pages were developed by John Avila SJSU CS Dept.