Getting to know Bash

What is bash?
What is a shell?
Redirecting input and output
Miscellaneous useful commands
For more information

What is bash?

`bash' stands for `Bourne Again SHell'. The Bourne shell was the original shell for UNIX: the ubiquitous `/bin/sh'. Bash is the GNU project's (free) re-implementation of the Bourne shell (with extra features, of course).

What is a shell?

A shell is just a command line interface between the user and the operating system. You type in what programs you want to run, and the shell runs them for you. Of course, shells generally allow you to do much more than this.

Here's an (incomplete) list of shells available for Unix-like operating systems:

sh ash bash csh tcsh ksh zsh rc es sash
bash, tcsh, zsh and ksh are probably the most popular these days. Here we look at bash, but (almost?) all the features covered here can be found in one form or another in the other popular shells.


Aliases provide short-cut commands. For example:
alias h=history
alias ls='/bin/ls -CF'
alias cp='/bin/cp -i'
alias mv='/bin/mv -i'
unalias rm
Bash only supports simple substitution in aliases; other shells' aliases can be considerably more complicated. However, the same effect can be achieved in bash by using shell functions. For example:
lm() { /bin/ls -Flag $* | /bin/more }
... but shell programming is a large topic on its own.


Most shells (except the truly ancient, such as the original Bourne shell), have some kind of history capability. That is, they can remember the last n commands you entered, and allow you to retrieve and/or modify them for reuse. The last m commands are also saved between shell sessions.

Bash supports two different kinds of history. One comes from its use of the GNU `readline' library. This allows one to scroll up and down the history, searching, copying, modifying, etc. using emacs-like (or vi-like if you prefer) key bindings.

The other is similar to the history expansion provided by `csh' and its derivatives. Some examples:

!! The previous command
!-5 The fifth last command
!372 Command number 372
!foo The last command starting with `foo'
!?bar? The last command containing the string `bar'
^foo^bar The previous command, with `foo' replaced by `bar'
!^ The first argument of the previous command
!$ The last argument of the previous command
!* All the arguments of the previous command
!?foo?:3:h:gs/bar/baz/ Argument 3 of the last command containing the string `foo' with the trailing pathname component stripped off and all occurrences of `bar' replaced by `baz'

The current history list can be displayed with the `history' command.


Most modern shells allow some form of "name completion". In its basic form, it allows the user to type in a partial command or file name, and have the shell attempt to complete it for them. Bash's standard completion facilities can be invoked by hitting the `tab' key at any point on the command line. If the completion is unique, it is added to the command line. Otherwise, as much as possible is completed; hitting tab again results in a list of possible completions being printed.

Bash tries to be smart about its completion. If the word being completed starts with `$', it tries completing it as a shell variable. If it starts with a `~', it tries completing it as a user name. If it starts with a `@', it tries completing it as a host name. When appropriate, it tries completing it as a command (including aliases and functions). When all of the above don't work, it tries filename completion. (Note that there are key bindings for doing all of the above specifically, including just printing the options rather than performing the completion.)

Globbing (pathname expansion)

Expansion of wildcards (`?', `*', etc.) is usually performed by the shell in Unix-like operating systems. This means they are treated consistently across all programs. Some examples:
* All files (except those starting with `.')
foo*bar All files starting with `foo' and ending with `bar'
ba? All three-character files starting with `ba'
foo?*bar All files starting with `foo' and ending with `bar' with at least one character between them
[A-Z]* All files starting with a capital letter
*.[ch] All files ending in `.c' or `.h'
*[^0-9] All files which don't end in a number

If the pattern matches at least one file, it is replaced by the matching file(s) (in sorted order). If there are no matches, the pattern is left as it is.

Related to the above is `brace expansion', though this does not match against files (unless wildcards appear in the result). Examples:

a{b,c,d}e Expands to `abe ace ade'
/usr/{bin,lib,man} Expands to `/usr/bin /usr/lib /usr/man'
/usr/{,local/}{bin,lib,man} Expands to `/usr/bin /usr/lib /usr/man /usr/local/bin /usr/local/lib /usr/local/man'

Redirecting input and output

Normally the shell takes the input for the program from the "keyboard", and sends the results to the "screen" (loosely speaking). Bash (and other shells derived from the Bourne shell) has quite sophisticated means for controlling where input comes from and where output goes to, but most of this power is overkill for most interactive use. Here's some relatively simple examples:
foo > bar Redirects the output of `foo' to the file `bar'
foo 2> bar Redirects the error output of `foo' to the file `bar'
foo >> bar Appends the output of `foo' to the file `bar', rather than clobbering it
foo < bar Causes `foo' to read its input from the file `bar'
foo | snafu Takes the output of `foo' and feeds ("pipes") it into `snafu' as input

The `2' in `2>' above refers to a `file descriptor'.  Standard file descriptor numbers:

0 Standard input
1 Standard output
2 Standard error

You can also "copy" file descriptors:

foo 2>&1 Sends the error output to the same place as the standard output (useful for sending both to the same place)

Redirections can be combined, but the order can be important:

foo > bar 2> baz Redirects the output of `foo' to the file `bar', and the error output to the file `baz'
foo > bar 2>&1 Redirects the output of `foo' to the file `bar', and then redirects the error output to the same place
foo 2>&1 > bar Redirects the error output to where the standard output (was) going, and then redirects the standard output (only) to `bar'
foo &> bar Same as `foo > bar 2>&1' (short-cut)
foo 2>&1 | snafu Pipes both the standard output and the error output of `foo' into the input of `snafu' (the pipe redirection is always done first, so when the error output is sent to the same place as the standard output, the standard output is already being sent to the pipe)


Some characters have special meaning to the shell:
| & ; ( ) < > $ ` ' " \ space tab
These have to be "quoted" if they are not intended to be interpreted by the shell. One way to do this is to precede the character by a backslash (\). Another way is to enclose all or part of a string within quotation marks. Note that the different quotation marks have different meanings.
'...' Everything within the string is kept verbatim
"..." Most things kept verbatim: dollar ($) and backquotes (`) still special
`...` Not to be confused with '...'!  This executes the enclosed string as if it were a command and replaces it with the command's output

Compare the following commands:

echo 'rm -rf *' ; sleep 5
echo `rm -rf *` ; sleep 5

Miscellaneous useful commands

pwd Print the current directory
pushd "Push" the current directory onto the directory stack and change to another directory
popd "Pop" the current directory off the directory stack
dirs Print the directory stack
tee Copy its input to a file as well as printing it on standard output
echo Print its arguments on standard output

For more information

The `man' page for bash is big and daunting, but it is comprehensive, and quite good compared to many.  Pipe it into less or something (`man bash | less') so you can scroll around easily and perform simple searches.

If you're familiar with `info' or `emacs', you may also like to look at the info page (`info bash').

O'Reilly have a book on bash, `Learning the bash Shell' (2nd ed), but I've not seen it so can't really comment.

There are no doubt many net resources around.  As an undergrad, I found Zoltan Somogyi's lectures on shell programming quite useful.  He has some lecture notes available (slide set #2), as well as some sample shell scripts.