Shells: which one you are in, and how to leave it
◈ 7 cardsThe major UNIX shells and the axes they are compared on; login shell versus subshell; and the concrete Bourne-family / C-shell-family differences an exam asks for.
What a shell is
A shell is a program, nothing more exotic than that. It reads a line, splits it on whitespace, expands the metacharacters, finds the program you named, asks the kernel to run it, waits for it to finish, and prints a prompt. It sits at the shell layer of the architecture, squarely in the AUI, and it is also a programming language in its own right — which is why the second half of this course is spent writing scripts in it.
A command is either internal (built into the shell itself — cd, echo, set, exit) or external (a separate program on disk — ls, cp, grep). For an external command the shell walks the directories named in your search path, in order, first match wins, and runs the first executable of that name it finds. This is why PATH order is a security question as well as a convenience one.
The shells you should be able to name
sh— the Bourne shell, Steven Bourne, shipped in the Seventh Edition in 1979. The baseline scripting language; the default on many System V systems.csh— the C shell, Bill Joy, late 1970s, first widely available in 2BSD. Gave the shell a C-like scripting syntax, and introduced job control and history.ksh— the Korn shell, David Korn, official in SVR4 in 1986. A superset of the Bourne shell, with the useful C-shell ideas folded in.bash— the Bourne-Again shell, the GNU project's Bourne-compatible shell and the default login shell on essentially every Linux distribution, which means yours.tcsh— the C shell plus command-line editing and completion.
(zsh and rc exist too and sit awkwardly in either family; naming them is a bonus, not a requirement.)
The three axes the book compares shells on, and the axes an exam answer should use, are command execution, I/O handling, and programming. Compare two shells on the same axes or the comparison is not a comparison.
Worked example: stacking a shell and failing to log out of it
Start by asking which shell you were given at login:
$ echo $SHELL
/bin/bash
Your login shell is set in your account record by the administrator; $SHELL reports it. Now start another shell on top of it:
$ sh
$ ps -o pid,comm
PID COMMAND
2841 bash
2903 sh
2911 ps
There are now two shells alive. The bash is your login shell, sitting blocked in wait; the sh is a subshell, a child process, and it is the one reading your keystrokes. Stack a third and ps will show three. Nothing was replaced — you built a pile.
Now try to leave the way you leave a session:
$ logout
sh: logout: not login shell: use `exit'
Refused, and the message names the reason. logout is meaningful only in a login shell. To leave a subshell you type exit, or press Ctrl-D on an empty line, which sends end-of-input. Do that once per shell you stacked; only when you are back in the login shell will logout work. Forgetting this is the single most common way people conclude their terminal has hung.
To change your login shell permanently, use chsh — on Linux and on BSD. (Solaris has no chsh; there the administrator edits your account record.) Running a shell by name, as above, is only ever temporary.
The two families, and where they actually differ
The Bourne family (sh, ksh, bash) and the C-shell family (csh, tcsh) are not dialects of one language; they are two languages that happen to run the same external commands. Four differences are worth memorising, because they are the ones that make a script written for one fail in the other.
Search path. Bourne family: PATH is a single colon-separated string, PATH=/usr/bin:/bin:$HOME/bin. C shell: path is a lower-case word list in parentheses, set path = (/usr/bin /bin ~/bin). Different name, different type, different separator.
Variables. Bourne family: VAR=value with no spaces around the =, then export VAR to put it in the environment. C shell: set var = value for a shell variable, setenv VAR value for an environment one — and here the spaces around = are required rather than forbidden.
Exit status. Bourne family: the status of the last command is in $?. C shell: it is in $status. Some textbooks print $? for both; that is wrong, and it is wrong in a way that fails silently — $? in csh is an undefined-variable reference, not a zero.
Start-up files. The two kinds are not interchangeable, and module 3 makes the distinction the examinable point. A login file runs once, when you log in: .profile for the Bourne family (bash reads .bash_profile first if it exists), .login for the C shell. An rc file runs for every shell that starts: .bashrc for bash, .cshrc for csh. So .profile is a login file — never call it an rc file. Aliases and prompt settings belong in the rc file, because a subshell reads that one and inherits nothing from the login file; PATH and umask belong in the login file, because they are inherited.
The prompt character ($ for the Bourne family, % for the C shell) is a real difference too, but it is a cosmetic one — if you can only offer that, offer one of the four above instead.