Chapter 7. The Bash shell

Table of Contents
7.1. Introduction
7.2. Starting the shell
7.3. Shell basics

7.1. Introduction

The shell is the traditional interface used by UNIX and GNU/Linux. In contrast to the X Window System it is an interface that works with commands. In the beginning this can be a bit awkward, but the shell is very powerful. Even in these days the shell is almost unavoidable ;).

The default shell on Slackware Linux is Bash. Bash means "Bourne-Again SHell", which is a pun on the name of one of the traditional UNIX shells, the "Bourne Shell". Slackware Linux also provides some other shells, but Bash is the main topic of this chapter.

7.2. Starting the shell

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 are using a graphical login manager like gdm, log on as you would normally, and look in your window manager or desktop environment menu for an entry named "XTerm". XTerm is a terminal emulator, after the terminal emulator is started the shell comes up.

The shell might remind some people of MS-DOS. Be happy, it has nothing to do with DOS, the only similarity is that you can enter commands ;).

7.3. Shell basics

This chapter might be a difficult to read for the first time, because you might not know any shell commands. Many important commands are described in the next chapters, but those chapters are not really useful without any knowledge of the shell. So, it is not a bad idea to browse quickly through this chapter, and the next few chapters, to get an idea what this shell thing is all about. After that quick overview you should be able to understand this chapter.

7.3.1. Executing commands

The most important job for the shell is to execute your commands. Let's look at a simple example. Most UNIX variants have a command named whoami, which shows as which user you are logged in. Try typing whoami, and press the <Enter> after that. The <Enter> tells the shell that it should execute the command that you have typed on the current line. The output looks like this:


daniel@tazzy:~$ whoami
daniel
daniel@tazzy:~$

As you can see the control is handed back to the shell after the command is finished.

7.3.2. Browsing through shell commands

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 (till 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>.

7.3.3. Completion

Completion is one of the most useful functionalities of UNIX-like shells. Suppose that you have a directory with two files named websites and recipe. And suppose you want to cat the file websites (cat shows the contents of a file), by specifying websites as a parameter to cat. Normally you would type "cat websites", and execute the command. Try typing "cat w", and hit the <Tab> key. Bash will automatically expand what you typed to "cat websites".

But what happens if you have files that start with the same letter? Suppose that you have the recipe1.txt and recipe2.txt files. Type "cat r" and hit <Tab>, Bash will complete the filename as far as it can. It would leave you with "cat recipe". Try hitting <Tab> again, and Bash will show you a list of filenames that start with "recipe", in this case both recipe files. At this point you have to help Bash by typing the next character of the file you need. Suppose you want to cat recipe2, you can push the <2> key. After that there are no problems completing the filename, and hitting <Tab> completes the command to "cat recipe2.txt".

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 practive with using the touch command. For example, to make a file named recipe3.txt, execute touch recipe3.txt.

7.3.4. Wildcards

Most shells, including Bash, 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-1. Bash wildcards

Wildcard Matches
* A string of characters
? A single character
[] A character in an array of characters

7.3.4.1. Matching a string 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*

7.3.4.2. Matching single characters

The "?" wildcard works as the "*" wildcard, but matches single characters. Suppose that we have three files, file1.txt, file2.txt and file3.txt. The string file?.txt matches all three of these files, but it does not match file10.txt ("10" are two characters).

7.3.4.3. Matching characters from a set

The "[]" wildcard matches every character between the brackets. Suppose we have the files from the previous example, file1.txt, file2.txt and file3.txt. The string file[23].txt matches file2.txt and file3.txt, but not file1.txt.

7.3.5. Redirections and pipes

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

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.

7.3.5.1. Redirection

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 md5sums 
6be249ef5cacb10014740f61793734a8  test1
220d2cc4d5d5fed2aa52f0f48da38ebe  test2
631172a1cfca3c7cf9e8d0a16e6e8cfe  test3

As we can see in the cat output the output of the md5sum * output was redirected to the md5sums file. We can also use redirection to provide input to a command:


$ md5sum < test1
6be249ef5cacb10014740f61793734a8  -

This feeds the contents of the test1 to md5sum.

7.3.5.2. pipes

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 shows a schematic overview of a pipeline consisting of two commands.

Figure 7-2. A pipeline

The "syntax" of a pipe 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. The output of the cat command is piped to grep, which prints out all files containing the phrase "aba". In turn, the output of "grep" is piped to wc -l, which counts the number of lines it receives from stdin. Finally, when the stream is finished wc prints the number of lines it counted. So, combined three commands to count the number of words containing the phrase "aba" in this particular dictionary.

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.