The inside of Athena Unix
Today we will continue discussing the shell. We will start by covering the differences between the different shells which are available.
There are 4 shells available on the various Athena machines:
. sh . csh . ncsh . tsh
Actually, when you run csh on Athena, you are really running ncsh. The major difference between the two is that ncsh allows you to use command completion (esc) to complete program names or file names. In the rest of this lecture, when I refer to csh, I am really talking about both csh and ncsh.
sh is the „standard“ shell used under UNIX (but not Athena UNIX). You will often hear it refered to as the bourne shell. The bourn shell does pretty much what you would expect a shell to do. You will find that most shell scripts are written in using the bourne shell.
csh is the shell that most of you probably use if your use of UNIX is on Athena. We discussed some of the builtin commands for that shell. Of course, you can also issue the usuall UNIX commands (which are actually programs) from the c-shell too (just as you can from the bourne shell). Let me list some of the differences between the c shell and the bourne shell.
The c shell has a history mechanism. If you set the history variable to a number, it will remember that number of previous commands, and you can use the history to reissue the commands, even make changes to them before reisuing them, or fixing mistakes. Another difference brought about by the use of ! for history is that if you really want to use an ! in the command line, it has to be quoted.
. use of ~
The c shell allows you to specify a users directory as ~user. The ~user is actually expanded by the shell to the full path of his/her login directory. The c shell reads .login when you log in instead of the file .profile which is ready by the bourne shell. Similarly, the shell init file is .cshrc instead of .shrc.
Last I mentioned how the alias command could be used to declare a synonym for another command (or sequence of commands). It too is one of the differences between the c shell and the bourne shell.
The last shell I mentioned was the t shell. tsh is similar to ncsh except it has a few (more) added features. One of the added features is an emacs like history mechanism. To edit previous commands emacs editing commands can be used. I don’t think that tsh is available on any of the Athena machines except Charon. Use the man command to find out more about each of the shells I mentioned.
Environments and Variables
There are two commands in the c shell that can be used to set variables. They are
set and setenv
set is relatively straight forward. You can set the value of a variable to be a string. These variables can then be used later in the shell by preceeding its name by $. For example, if I said
set var1 /mit/b/c/bcn/file1
I could later edit that file by saying
Some variables are used by the shell itself. For example, the value of the „history“ variable specifies how many lines of history are to be kept. A few other variables used by the shell are
notify = immediatly tell of changes in process states
time = if a command user more than time cpu seconds, it gives stats on usage upon completion
prompt = your prompt
It is important to note that the values of the variables set by the set command are not available to programs which you run under the shell. In order to have the values visible to the programs you run it is necessary to use the setenv command. When a variable is set using the setenv command, its name and value is added to a string (usually quite long) which is automatically available to programs running under the shell.
A few useful variables in your environment are:
Variables can be unset using the unset and unsetenv commands. You environment can be seen using the printenv command.
As I mentioned before, the c shell provides a history mechanism whereby you can repeat previous commands, and or change them or correct them and then reissue them. The variable „history“ should be set to the number of lines of history that you wish the shell to maintain.
The command „history“ will list those commands that are remembered. In order to reuse a command, the shell uses the „!“ character. By far the simples form of this is the „!!“ command which is replaced by the last command.
!word is replaced by the last command line beginning with that word.
!number is replaced by the command line whose number (listed by
history) is number.
!$ is replaced by the last word of the previous command
There are many more commands which can be used to modify previous commands. For instance, !mv:s/foo/bar/ will find the line beginning with mv, and it will replace foo by bar, and then execute the command. I refer you to the c shell manual page for more commands.
If you have a .history file, the shell will remember your previous commands between logins. In other words, you can log out, and back in, and it will remember the command you typed in you previous login session.
I should also mention here that the command editing in the t shell uses emacs like editor commands.
How is it that the shell runs other programs. A little background is in order first. Under UNIX, the only way to create a new process is with the „fork“ system call. What the fork system call does is it creates a new process which is a copy of the current process.
Another uaseful system call is the „execute“ system call. The execute system call takes as arguments a filename, and a list of arguments. It then replaces the current program with the contents of the filename specified as the program, passing it the arguments which were specified.
When a shell wants to run a new process, the fist thing it does is it tries to open the standard output and standard input if either has been redirected. It then forks. Each fork then checks to determine if it was the parent process or the child. The parent process then waits for the child to finish (or for the user to type ^Z), while the child uses the execute system call to replace itself with the desired program.
When a sequence of programs are specified in a pipeline, the shell starts the first process as described above. For the standard output, it opens pipe pretty much as it would open a file. The process created by fork then has access to the pipe as the standard output. The next thing the shell does is it changes the descriptor for the pipe from the standard output (file 2) to the standard input (file 1), and starts the second program in the pipe as it would do so normally. Becuase of the way open files are passed to child processes, the standard input for the second program is in fact, the same file descriptor (or pipe) as the standard output to the first program.
Expending this mechanism to a three program pipeline should be failry straightforward.
Stoping and starting programs-
The shell keeps track of those processes which are running under it. The jobs command can be used to list them. The shell commands stop, fg, bg, and a few other commands can be used to start and stop these processes. bg tells the shell to start a child process in the background. Background processes are unable to read from the terminal, but they can write to it. The fg command tells the shell to run the process in foreground. A foreground process (often considered the current process) has control of the terminal. Hence, when a process is running in forground, the shell waits for it to finish before returning you to the shell.