Table of Contents
In this chapter we will look at the traditional working environment of UNIX systems: the shell. The shell is an interpreter that can be used interactively and non-interactively. When the shell is used non-interactively it functions as a simple, but powerful scripting language.
The procedure for starting the shell depends on whether you use a graphical or text-mode login. If you are logging on in text-mode the shell is immediately started after entering the (correct) password. If you use a graphical login manager like KDM, log on as you would normally, and look in your window manager or desktop environment menu for an entry named “XTerm”, “Terminal” or “Konsole”. XTerm is a terminal emulator, after the terminal emulator is started the shell comes up.
Before we go any further, we have to warn you that Slackware Linux provides more than just one shell. There are two shell flavors that have become popular over time, the Bourne shell and the C shell. In this chapter we will describe Bourne shells that conform to the IEEE 1003.1 standard. The Bash (Bourne Again Shell) and ksh (Korn Shell) shells conform well to these standards. So, it is a good idea to use one of these two shells. You can easily see what shell the system is running by executing echo $SHELL. This is what a Bash shell may report:
$ echo $SHELL
/bin/bash
If you are using a different shell, you can change your default shell. Before setting a different shell, you have to establish the full path of the shell. You can do this with the which command. For example:
$which bash/bin/bash $which ksh/bin/ksh
On this Slackware system, the full path to the bash shell is
/bin/bash/bin/ksh
$ chsh -s /bin/bash
Changing shell for daniel.
Password:
Shell changed.
The new shell will be activated after logging out from the current shell (with logout or exit), or by opening a new X terminal window if you are running X11.
An interactive shell is used to start programs by executing commands. There are two kinds of commands that a shell can start:
Built-in commands: built-in commands are integrated in the shell. Commonly used built-in commands are: cd, fg, bg, and jobs.
External commands: external commands are programs that are not part of the shell program, and are separately stored on the filesystem. Commonly used external commands are: ls, cat, rm, and mkdir.
All shell commands are executed with the same syntax:
commandname [argument1 argument2 ... argumentn]
The number of arguments is arbitrary, and are always passed to the command. The command can decide what it does with these arguments.
All built-in commands can always be executed, because they are part of the shell. External commands can be executed by name when the program is in the search path of the shell. Otherwise, you will have to specify the path to the program. The search path of the shell is stored in a variable named PATH. A variable is a named piece of memory, of which the contents can be changed. We can see the contents of the PATH variable in the following manner:
$ echo $PATH
/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/daniel/bin
The directory paths in the PATH variable are separated with the colon (:) character. You can use the which command to check whether a given command is in the current shell path. You can do this by providing the command as an argument to which. For example:
$which pwd/bin/pwd $which sysstat/usr/bin/which: no sysstat in (/usr/kerberos/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:/home/daniel/bin)
If a program is not in the path, you can still run it by entering its absolute or relative path.
It is often necessary to jump through various parts of a line, and to alter it, when you are editing larger commands. Both bash and ksh have keyboard shortcuts for doing common operations. There are two shell modes, in which the shortcut keys differ. These modes correspond with two popular editors for UNIX in their behavior. These editors are vi and emacs. In this book we will only cover the EMACS-like keystrokes. You can check in which mode a shell is running by printing the SHELLOPTS variable. In the first example the shell is used in emacs mode, in the second example the vi mode is used. You identify the mode by looking for the emacs or vi strings in the contents of the variable.
$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
$ echo $SHELLOPTS
braceexpand:hashall:histexpand:history:interactive-comments:monitor:vi
If your shell is currently using the vi mode, you can switch to the emacs mode by setting the emacs option:
$ set -o emacs
With the emacs editing mode enabled, you can start using shortcuts. We will look at three kinds of shortcuts: character editing shortcuts, word editing shortcuts, and line editing shortcuts. Later in this chapter, we will also have a look at some shortcuts that are used to retrieve entries from the command history.
The first group of shortcuts have characters as their logic unit, meaning that they allow command line editing operations on characters. Table 7.1, “Moving by character” provides an overview of the shortcuts that are used to move through a line by character.
Table 7.1. Moving by character
| Keys | Description |
|---|---|
| Ctrl-b | Move a character backwards. |
| Ctrl-f | Move a character forward. |
These shortcuts are simple, and don't do anything unexpected. Suppose that you have typed the following line:
find ~/music -name '*.ogg' - -print
The cursor will be at the end. You can now move to the start of the line by holding Ctrl-b:
find ~/music - -name '*.ogg' -print
Likewise, you can go back again to the end by holding Ctrl-f. There is an error in this line, since there is one erroneous dash. To remove this dash, you can use one of the character deletion shortcuts.
Table 7.2. Deleting characters
| Keys | Description |
|---|---|
| Ctrl-h | Delete a character before the cursor. This has the same effect as using the Backspace key on most personal computers. |
| Ctrl-d | Delete the character the cursor is on. |
You can delete the dash in two manners. The first way is to move the cursor to the dash:
find ~/music - -name '*.ogg' -print
and then press Ctrl-d twice. This will delete the dash character, and the space that follows the dash:
find ~/music -name '*.ogg' -print
Looking at the original fragment, the other approach is to position the cursor on the space after the dash:
find ~/music - -name '*.ogg' -print
and then press Ctrl-h twice to delete the two preceding characters, namely the dash and the space before the dash. The result will be the same, except that the cursor will move:
find ~/music -name '*.ogg' -print
One of the nice features of most modern shells is that you can transpose (swap) characters. This is handy if you make a typing error in which two characters are swapped. Table 7.3, “Swapping characters” lists the shortcut for transposing characters.
Table 7.3. Swapping characters
| Keys | Description |
|---|---|
| Ctrl-t | Swap (transpose) the characters the cursor is on, and the character before the cursor. This is handy for quickly correcting typing errors. |
Suppose that you have typed the following command:
cat myreport.ttx
The extension contains a typing error if you intended to
cat myreport.txt
cat myreport.ttx
You can then press Ctrl-t. The characters will be swapped, and the cursor will be put behind the swapped characters:
cat myreport.txt
It if often tedious to move at character level. Fortunately the Korn and Bash shells can also move through lines at a word level. Words are sequences of characters that are separated by a special character, such as a space. Table 7.4, “Moving by word” summarizes the shortcuts that can be used to navigate through a line by word.
Table 7.4. Moving by word
| Keys | Description |
|---|---|
| Esc b | Move back to the start of the current or previous word. |
| Esc f | Move forward to the last character of the current or next word. |
As you can see the letters in these shortcuts are equal to those of moving forward and backwards by character. The movement logic is a bit curious. Moving forward puts the cursor to the end of the current word, not to the first character of the next word as you may have predicted. Let's look at a quick example. In the beginning the cursor is on the first character of the line.
find ~/music -name '*.ogg' -print
Pressing Esc f will move the cursor behind the last character of the first word, which is find in this case:
find ~/music -name '*.ogg' -print
Going forward once more will put the cursor behind ~/music:
find ~/music -name '*.ogg' -print
Backwards movement puts the cursor on the first character of the current word, or on the first character of the previous word if the cursor is currently on the first character of a word. So, moving back one word in the previous example will put the cursor on the first letter of “music”:
find ~/music -name '*.ogg' -print
Deleting words works equal to moving by word, but the characters that are encountered are deleted. Table 7.5, “Deleting words” lists the shortcuts that are used to delete words.
Table 7.5. Deleting words
| Keys | Description |
|---|---|
| Alt-d | Delete the word, starting at the current cursor position. |
| Alt-Backspace | Delete every character from the current cursor position to the first character of a word that is encountered. |
Finally, there are some shortcuts that are useful to manipulate words. These shortcuts are listed in Table 7.6, “Modifying words”.
Table 7.6. Modifying words
| Keys | Description |
|---|---|
| Alt-t | Swap (transpose) the current word with the previous word. |
| Alt-u | Make the word uppercase, starting at the current cursor position. |
| Alt-l | Make the word lowercase, starting at the current cursor position. |
| Alt-c | Capitalize the current word character or the next word character that is encountered. |
Transposition swaps words. If normal words are used, it's behavior is predictable. For instance, if we have the following line with the cursor on “two”
one two three
Word transposition will swap “two” and “one”:
two one three
But if there are any non-word characters, the shell will swap the word with the previous word while preserving the order of non-word characters. This is very handy for editing arguments to commands. Suppose that you made an error, and mixed up the file extension you want to look for, and the print parameter:
find ~/music -name '*.print' -ogg
You can fix this by putting the cursor on the second faulty word, in this case “ogg”, and transposing the two words. This will give the result that we want:
find ~/music -name '*.ogg' -print
Finally, there are some shortcuts that change the capitalization of words. The Alt-u shortcut makes all characters uppercase, starting at the current cursor position till the end of the word. So, if we have the lowercase name “alice”, uppercasing the name with the cursor on “i” gives “alICE”. Alt-l has the same behavior, but changes letters to lowercase. So, using Alt-l on “alICE” with the cursor on “I” will change the string to “alice”. Alt-c changes just the character the cursor is on, or the next word character that is encountered, to uppercase. For instance, pressing Alt-c with the cursor on “a” in “alice” will yield “Alice”.
The highest level we can edit is the line itself. Table 7.7, “Moving through lines” lists the two movement shortcuts.
Table 7.7. Moving through lines
| Keys | Description |
|---|---|
| Ctrl-a | Move to the beginning of the current line. |
| Ctrl-e | Move to the end of the current line. |
Suppose that the cursor is somewhere halfway a line:
find ~/music -name '*.ogg' -print
Pressing Ctrl-e once will move the cursor to the end of the line:
find ~/music -name '*.ogg' -print
Pressing Ctrl-a will move the cursor to the beginning of the line:
find ~/music -name '*.ogg' -print
You can also delete characters by line level. The shortcuts are listed in Table 7.8, “Deleting lines”. These shortcuts work like movement, but deletes all characters that are encountered. Ctrl-k will delete the character the cursor is on, but Ctrl-x Backspace will not. Moving to the beginning of the line with Ctrl-a, followed by Ctrl-k, is a fast trick to remove a line completely.
Table 7.8. Deleting lines
| Keys | Description |
|---|---|
| Ctrl-k | Delete all characters in the line, starting at the cursor position. |
| Ctrl-x Backspace | Delete all characters in the line up till the current cursor position. |
It often happens that you have to execute commands that you executed earlier. Fortunately, you do not have to type them all over again. You can browse through the history of executed commands with the up and down arrows. Besides that it is also possible to search for a command. Press Control-r and start typing the command you want to execute. You will notice that bash will display the first match it can find. If this is not the match you were looking for you can continue typing the command (until it is unique and a match appears), or press Control-r once more to get the next match. When you have found the command you were looking for, you can execute it by pressing <Enter>.
Completion is one of the most useful functionalities of
UNIX-like shells. Suppose that you have a directory with two
files named websitesrecipewebsiteswebsites
But what happens if you have files that start with the same
letter? Suppose that you have the
recipe1.txtrecipe2.txtrecipe2
It is worth noting that completion also works with commands. Most GNU/Linux commands are quite short, so it will not be of much use most of the time.
It is a good idea to practice a bit with completion, it can save
alot of keystrokes if you can handle completion well. You can
make some empty files to practice with using the
touch command. For example, to make a file
named recipe3.txt
Most shells, including Bash and ksh, support wildcards. Wildcards are special characters that can be used to do pattern matching. The table listed below displays some commonly used wildcards. We are going to look at several examples to give a general idea how wildcards work.
Table 7.9. Bash wildcards
| Wildcard | Matches |
|---|---|
| * | A string of characters |
| ? | A single character |
| [] | A character in an array of characters |
As you can see in the table above the “*” character matches a string of characters. For example, *.html matches everything ending with .html, d*.html matches everything starting with a d and ending with .html.
Suppose that you would like to list all files in the current directory with the .html extension, the following command will do the job:
$ ls *.html
book.html installation.html pkgmgmt.html usermgmt.html
filesystem.html internet.html printer.html xfree86.html
gfdl.html introduction.html proc.html
help.html slackware-basics.html shell.html
Likewise we could remove all files starting with an in:
$ rm in*
The “?” wildcard works as the “*”
wildcard, but matches single characters. Suppose that we have
three files, file1.txtfile2.txtfile3.txtfile10.txt
One of the main features of UNIX-like shells are redirections and pipes. Before we start to look at both techniques we have to look how most UNIX-like commands work. When a command is not getting data from a file, it will open a special pseudo-file named stdin, and wait for data to appear on it. The same principle can be applied for command output, when there is no explicit reason for saving output to a file, the pseudo-file stdout will be opened for output of data. This principle is shown schematically in Figure 7.1, “Standard input and output”
You can see stdin and stdout in action with the cat command. If cat is started without any parameters it will just wait for input on stdin and output the same data on stdout. If no redirection is used keyboard input will be used for stdin, and stdout output will be printed to the terminal:
$ cat
Hello world!
Hello world!
As you can see cat will print data to stdout after inputting data to stdin using the keyboard.
The shell allows you to take use of stdin
and stdout using the “<”
and “>”. Data is redirected in which way the
sharp bracket points. In the following example we will
redirect the md5 summaries calculated for a set of files to a
file named md5sums
$md5sum * > md5sums$cat md5sums6be249ef5cacb10014740f61793734a8 test1 220d2cc4d5d5fed2aa52f0f48da38ebe test2 631172a1cfca3c7cf9e8d0a16e6e8cfe test3
As we can see in the cat output the output
of the md5sum * output was redirected to
the md5sums
$ md5sum < test1
6be249ef5cacb10014740f61793734a8 -
This feeds the contents of the test1
You can also connect the input and output of commands using so-called pipes. A pipe between commands can be made with the “|” character. Two or more combined commands are called a pipeline. Figure 7.2, “A pipeline” shows a schematic overview of a pipeline consisting of two commands.
The “syntax” of a pipeline is: command1 | command2 ... | commandn. If you know how the most basic UNIX-like commands work you can now let these commands work together. Let's look at a quick example:
$ cat /usr/share/dict/american-english | grep "aba" | wc -l
123
The first command, cat, reads the
dictionary file
/usr/share/dict/american-english
There are hundreds of small utilities that handle specific tasks. As you can imagine, together these commands provide a very powerful toolbox by making combinations using pipes.