Guide to BASH Operation and Scripting

All the information here is presented without any warranty or guarantee of accuracy. Use it at your own risk. When in doubt, please consult the man pages or the GNU info pages as the authoritative references.

["BASH"] is a BourneShell compatible shell, which adds many new features to its ancestor. Most of them are available in the KornShell, too. If a question is not strictly shell specific, but rather related to Unix, it may be in the UnixFaq.

TableOfContents

Introduction

This guide aims to become a point of reference for people interested in learning to work with ["BASH"]. It aspires to teach its readers good practice techniques in developing scripts for the ["BASH"] interpreter and educate them about the internal operation of ["BASH"].

This guide is targetted at beginning users. It assumes no basic knowledge, but rather expects you to have enough common sense to put two and two together. If something is unclear to you, you should report this so that it may be clearified in this document for future readers.

You are invited to contribute to the development of this document by extending it or correcting invalid or incomplete information.

A Definition

["BASH"] is an acronym for Bourne Again SHell. It is based on the Bourne shell and is mostly compatible with its features.

Shells are applications that provide users with the ability to interact with their operating system on an interactive level, or to allow them to execute batch processes quickly. In no way are they required for execution of processes, they are merely a layer between system function calls and the user.

Using ["BASH"]

Most users that think of ["BASH"] think of it as a prompt and a commandline. That is ["BASH"] in interactive mode. ["BASH"] can also run in non-interactive mode through scripts. We can use scripts to automate certain logic. Scripts are basically lists of commands that you can type on the commandline. When such a script is executed, all these commands are executed sequentially; one after another.

We'll start with the basics in an interactive shell. Once you're familiar with those, you can put them together in scripts.

The Basics

BASH takes commands on the commandline. Commands can be different things. They can be application executables, aliasses, function names, etc.

Each command can be followed by arguments. It is very important that you understand how this works exactly. If you don't grasp these concepts well, the quality of your code will degrade significantly and you will introduce very dangerous bugs. So, pay close attention in the next few chapters.

    $ ls
    a  b  c

ls is a command that lists files in the current directory.

    $ mkdir d
    $ cd d
    $ ls

mkdir is a command that creates a new directory. We specified the argument d to that command. This way, the application mkdir is instructed to create a directory called d. After that, we use the application cd to change the current directory to d. ls shows us that the current directory (which is now d) is empty, since it doesn't display any filenames.

Commandline Argument Splitting

Commands in ["BASH"] can take multiple arguments. These arguments are used to tell the command exactly what it's supposed to do. In ["BASH"], you separate these arguments by whitespace (spaces, tabs and newlines).

    $ ls
    $ touch a b c
    $ ls
    a  b  c

touch is an application that changes the 'Last Accessed'-time of a certain file to the current time. If the filename that it's given does not exist yet, it simply creates that file, as a new and empty file. In this example, we passed three arguments. touch creates a file for each argument. ls shows us that three files have been created.

    $ rm *
    $ ls
    $ touch a   b c
    $ ls
    a  b  c

rm is an application that removes all the files that it was given. * is a glob. It basically means all files in the current directory. You will read more about this later on.

Now, did you notice that there are several spaces between a and b, and only one between b and c? Also, notice that the files that were created by touch are no different than the first time. You now know that the amount of whitespace between arguments does not matter. This is important to know. For example:

    $ echo This is a test.
    This is a test.
    $ echo This    is    a    test.
    This is a test.

In this case, we provide the echo command with four arguments. 'This', 'is', 'a' and 'test.'. echo takes these arguments, and prints them out one by one with a space inbetween. In the second case, the exact same thing happens. The extra spaces make no difference. To protect the whitespace properly, we need to pass the sentence as one single argument. We can do this by using quotes:

    $ echo "This    is    a    test."
    This    is    a    test.

Quotes group everything together and pass it as a single argument. This argument is 'This is a test.', properly spaced. echo prints this single argument out just like it always does.

Be very careful to avoid the following:

    $ ls
    The secret voice in your head.mp3  secret
    $ rm The secret voice in your head.mp3
    rm: cannot remove `The': No such file or directory
    rm: cannot remove `voice': No such file or directory
    rm: cannot remove `in': No such file or directory
    rm: cannot remove `your': No such file or directory
    rm: cannot remove `head.mp3': No such file or directory
    $ ls
    The secret voice in your head.mp3

You need to make sure you quote filenames properly. If you don't you'll end up deleting the wrong things! rm takes filenames as arguments. If you do not quote filenames with spaces, rm things that each argument is another file. Since ["BASH"] splits your arguments at the spaces, rm will try to remove each word.

Please have a good look at http://bash-hackers.org/wiki/doku.php?id=syntax:words if all this isn't very clear to you yet.

Globs

Globs are a very important concept in ["BASH"], if only for their increadible convenience. Properly understanding globs will benefit you in many ways. Globs are basically patterns that can be used to match filenames or other strings.

Globs are composed of normal characters and meta characters. Meta characters are characters that have a special meaning. These are the basic meta characters:

Here's an example of how we can use glob patterns to expand to filenames:

    $ ls
    a  abc  b  c
    $ echo *
    a abc b c
    $ echo a*
    a abc

["BASH"] sees the glob, for example 'a*'. It expands this glob, by looking in the current directory and matching it against all files there. Any filenames that match the glob, are enumerated and replaced by the glob. As a result, the statement echo a* is replaced by the statement echo a abc, and is then executed.

BASH will always make sure that whitespace and special characters are escaped properly when expanding the glob. For example:

    $ touch "a b.txt"
    $ ls
    a b.txt
    $ rm *
    $ ls

Here, rm * is expanded into rm a\ b.txt. This makes sure that the string a b.txt is passed as a single argument to rm, since it represents a single file. It is important to understand that using globs to enumerate files is nearly always a better idea than using `ls for that purpose. Here's an example with some more complex syntax which we will cover later on, but it will illustrate the problem very well:

    $ ls
    a b.txt
    $ for file in `ls`; do rm "$file"; done
    rm: cannot remove `a': No such file or directory
    rm: cannot remove `b.txt': No such file or directory
    $ for file in *; do rm "$file"; done
    $ ls

Here we use the for command to go through the output of the ls command. The ls command results in a string a b.txt. The for command splits that string into arguments over which it iterates. As a result, for iterates over a and b.txt. Naturally, this is not what we want. The glob however expands in the proper form. It results in the string a\ b.txt, which for takes as a single argument.

["BASH"] also supports a feature called Extended Globs. These globs are more powerful in nature. This feature is turned off by default, but can be turned on with the shopt command, which is used to toggle shell options:

    $ shopt -s extglob

The list inside the paranthesis is a list of globs separated by the | character. Here's an example:

    $ ls
    names.txt  tokyo.jpg  california.bmp
    $ echo !(*jpg|*bmp)
    names.txt

Our glob now expands to anything that does not match the *jpg or the *bmp pattern. Only the text file passes for that, so it is expanded.