North Idaho Linux Users Group




Introduction to Bash

I. Introduction

I.a. What is Bash?

Bash (the Bourne Again SHell) is a command shell. It provides a way for the user to communicate to the Linux kernel, and for the kernel to communicate back to the user. When you enter something at the command prompt, that information is (usually) passed along to the kernel. The results are (usually) passed back to the Bash shell.

Like the MSDOS/Windows program, Bash is a command-language interpreter. Unlike, it is a very powerful program - one that provides enough power and utility to actually write program applications in.

The Bash shell has its own built-in interpretive programming language, which supports most of the programming constructs found in high-level languages, such as looping, functions, variables, and arrays. It has a set of built-in commands such as cd, echo and pwd. It can execute other programs, such as ps, find and grep.

I.b. Bash competitors

Unlike MSDOS/Windows, there is more than one command shell in Linux competing for your affections. Bash is probably the most popular, and is the default for most Linux distributions. Other shells available include the C-shell (csh), the Bourne Shell (bsh) and the Korn Shell (ksh).

All of these shells have their strengths and weaknesses. Bash seems to be the most well-rounded of the shells, providing strong input and processing capabilities.

II.a. Editing the command line

When you enter commands at the Bash prompt, you may often use command line completion to help you with the command. Here's how it works. Let's say you are user mburton and you are in a directory that contains a file called 'myverylongbashtalk.txt'. You want to copy that file to a directory called '/home/mburton/work'. You start entering the copy command like this:

cp myv

At this point, you don't have to type the rest of the file name - you can use command line completion to do that. Simply hit the Tab key, and if the first three letters you typed start only one file, that file will be displayed on the command line:

cp myverylongbashtalk.txt

If more than one file starts with those letters, Bash will beep at you and you can type a few more letters and press tab again.

To complete the command, we can type out the long path to the directory, or we can use a shortcut. In Bash, the tilde (~) means 'user home directory', so we can type

cp myverylongbashtalk.txt ~/work

instead of

cp myverylongbashtalk.txt /home/mburton/work

All of this built-in Bash capability is designed to make your life a bit easier.

If you need to edit a command because you've forgotten something or you made a mistake, you can do that using the backspace, delete, left and right arrow keys. Remember that Bash is always in 'insert' mode so if you type something in the middle of the command line, everything to the right is moved over to make room for the insertion.

Here is a list of some of Bash's command line editing keys:

TabComplete a file name if possible
BackspaceErase the character to the left of the cursor
DeleteErase the character under the cursor
Home, Ctrl-AGo to the start of the line
End, Ctrl-EGo to the end of the line
Left Arrow, Ctrl-BGo one character to the left (back)
Right Arrow, Ctrl-FGo one character to the right (forward)
Ctrl-KDelete from cursor to end of line
Ctrl-UDelete from cursor to start of line
Ctrl-WDelete one word to the left
Ctrl-YUndelete what was just deleted
Ctrl-LClear screen
Enter, Ctrl-MExecute the command line

Here is a list of how you can use the tilde as a shortcut:

~Substitute the contents of $HOME in the line
~userSubstitute the user's home directory
~+Substitute $PWD (current directory)
~-Substitute $OLDPWD (last current directory)

II.b. Controlling the command history

The Bash command line maintains a limited history of the commands you have entered. It maintains a unique history for each user, so if you switch users using the 'su' command, you will have a different history to work with.

The Bash command history is provided to reduce the amount of work you have to do to create a command line. If you want to do the same or similar command repetitively, you can pick up the command by navigating through the command history, make your changes and execute the command. Executed commands will be added to the command history.

There are a couple of ways to navigate through the command history. The easiest method is to use the up arrow and down arrow keys to scroll in the history.

If your history is long and you want to pick up a particular command, try using Ctrl-R. You press the Ctrl-R key, then the first letter of the command you want. A command starting with that letter will be displayed. If it is not the correct command, press Ctrl-R again and the next command in the history that starts with that letter will be displayed. Keep pressing Ctrl-R until you find the command line you want.

Here is a summary of the command history keys:

Up arrowDisplay the command line previous to the current one
Down arrowDisplay the command line next from the current one
Ctrl-R (letter)Display the command line starting with (letter)
Page UpGo to the start of the history
Page DownGo to the end of the history

You can also access the command line history using two Bash commands. The 'history' command will display all lines of the history. If you add a number to the history command, it will display the latest number of lines to be displayed, i.e.,

history 5

will display the last 5 lines of history.

The other command that accesses the comand line history is the 'fc' command. fc allows you to read the history and put the results in an editor, where you can make changes to it. You can then use the history command to write the changed history to the actual history file.

II.c. Wildcards

Whenever you enter a command in Bash, you can use 'wildcards' in the command. A wildcard is a special character or characters that will match anything. Wildcard characters used by bash are the asterisk '*', the question mark '?' and square brackets. The asterisk will match zero or more characters. The question mark will match a single character. The square brackets will match a specific range of characters. For instance, suppose we are in a directory that contains the following files:

If we want to list all the files that start with the word 'file', we would enter

ls file*

The asterisk will match all the characters following the 'file' part, which will list all the files except 'txtfile'. If we want to list just the 'txtfile', we could enter

ls *file

If we want all the files that end in '.txt', we would enter

ls *.txt

Note that the 'file3.TXT' file would not match the above request, since its extension is in upper case.

If we want to list all files with 'file' in them, regardless of position in the name, we could enter

ls *file*

We can use the question mark to make more detailed matches. If we wanted all the files that have a number in them, we could use

ls file?.*

The first and last file would not be listed. We could also use square brackets instead of the question mark, and put the character range in that we need:

ls file[0-9].*
ls file[123].*

These will both match the same way as the question mark.

Special note: The MSDOS shell also supports wildcard characters, but the two shells use them very differently. passes along the wildcard to whatever command it is executing. It is up to that command to expand and use the wildcard character.

On the other hand, Bash expands the wildcard on the command line before passing along the command line to the command. This means that the command does not need to do any work to expand the wildcard. For example, in the above directory, if you wanted to list the files that ended in numbers using, you would enter

dir file?.*

and it would pass the following to the dir built-in command


In Bash, you would enter

ls file?.*

and it would pass the following to the ls built-in command

file1.txt file2.txt file3.TXT

II.d. Aliases

An alias is a short command that Bash can translate to another longer command. For instance, let's say that you prefer to use the 'ls' command with the '-la' flags. We can define an alias for that and call it 'dir':

alias dir="ls -la"

We can then use the 'dir' command in place of the 'ls -la' command.

You can also use alias to redefine existing commands. Many distributions do this. For instance, have you ever tried to remove files and have Bash ask you if you want to remove each and every file? The 'rm' command has been redefined like this:

alias rm="rm -i"

which puts it in interactive mode.

Any commands that are redefined have been done in the .bashrc script, which starts up when you start up a Bash shell. There is a .bashrc script for each user in their home directory.

II.e. I/O redirection

Redirection allows the user to change the source or destination of data being used by a Bash command.

Commands or programs sometimes get their input from the console and send their output to the console. The source of data from the console is a stream called 'stdin'. The destination for output is a stream called 'stdout' and the destination for error messages is a stream called 'stderr'. I/O redirection allows you to change these sources/destinations to be other streams. You can get input from a file and send output to another file or even to the null device. Here is a list of I/O redirection characters:

>wordsend both stdout and stderr to 'word'
>&wordsend both stdout and stderr to 'word'
[n]<fileuse 'file' for input
[n]>fileuse 'file' for output
[n]>!filesame as '>', but overrides noclobber.
[n]>>filesame as '>&', but append data if file exists
[n]<>fileopen file for read/write
[n]<&mduplicate input file descriptor from m
[n]>&mduplicate output file descriptor from m
[n]<&-close input file descriptor
[n]>&-close output file descriptor

These redirection characters can be used on the command line, or in a script. The [n] allows you to open multiple streams simultaneously.

Example: list directory contents to a file named ''.

ls * >

Example: run the 'foo' command, getting the input from file '' and sending the output and error messages to the null device.

foo /dev/null


foo /dev/null 2>&1

II.f. Pipelines

Pipes allow you to feed the output of one command or program into another command or program as its input. The pipe character (|) is used to string these multiple commands together.

Example: Look for the string 'net' in the current programs that are running.

ps -ef | grep net

The output from the 'ps' command is fed to the 'grep' command. It then looks for a match to the string 'net'. If it finds one, that line is displayed.

II.g. Shell prompts

When you are interactively using Bash, the program prompts you for input by displaying a prompt. It does this by printing the primary prompt string $PS1. Whatever is stored in that string is used as the bash prompt. The prompt string has its own special characters that can be used to display some very informative prompts. The special characters are

Keys Command
\\athe ASCII BEL character. Beeps at you.
\\dthe date in Weekday Month Day format
\\ethe ASCII escape character (octal 033)
\\hthe hostname up to the first dot (.)
\\Hthe full hostname
\\nthe ASCII newline character
\\rthe ASCII carriage return character
\\sthe name of the shell
\\tthe time in 24-hour HH:MM:SS format
\\Tthe time in 12-hour HH:MM:SS format
\\uthe user's username
\\vthe version of the bash shell
\\Vthe version and patch level of the bash shell
\\wthe full path of the current working directory
\\Wthe current working directory only
\\!the history number of this command
\\#the command number of this command
\\$a '#' if the effective UID is 0, otherwise a '$'
\\@the time in 12-hour am/pm format
\\\\the backslash character
\\nnnthe ASCII character corresponding to the octal number nnn
\\[start a sequence of non-printing characters
\\]end a sequence of non-printing characters

You can use the escape character with VT-100 escape sequences to create colorful and useful command prompts.

II.h. The environment

Like the shell in MSDOS, Bash maintains an environment for each instance of itself. The environment contains shell settings in the form of environment variables. We have already touched on several of these ($HOME, $PWD, $PS1, etc.). Whenever a program is executed, that program receives a copy of the environment variables from the process which executes it.

You can display a list of the current environment by typing 'set'.

You can create new environment variables or change the values of old variables. To do this, simply type the name of the variable, an equals sign, and the value of the variable.

These environment variables have many uses. You can display them, test them or programs you are running can use them.

III. Bash Scripts

Bash has a built-in language you can use to create complex actions on your computer. When you put these actions in a file to be executed by Bash, it is called a 'shell script'. A shell script is basically a small program that is interpreted and executed by Bash.

III.a. Built-in Commands

Bash supports two kinds of commands - those that are built into the Bash shell, and those that are separate executable programs or scripts.

Here is a list of the commands that are built into Bash:

sourceread and execute commands from a file
:null command returning 0 exit status
aliascreate an alias
bgput a job in the background
binddisplay/modify 'readline' function and key bindings
breakexit from an enclosing for, while, until or select loop
builtinexecute a builtin command and return status
cdchange current directory
cd -change current directory to $OLDPWD
commandexecute a command with arguments
continuedo next iteration of for, while, until or select loop
declare typesetset attributes and values of variables
dirsdisplay the directory stack
disownremove jobs from the table of active jobs
echodisplay the rest of the line on the stdout device
enableenable/disable shell built-ins; load/unload new built-ins
evalevalute the rest of the line and execute the result
execexecute the rest of the line in place of the shell
exitexit from a shell script with a return value
exportno args - print names and values of exported variables with args - export variable to the environment
fcprint range of history commands
fgput a job into the foreground
getoptsparse parameters and options
hashno args - print the hash table contents with args - add a name to the hash table
helpprint help for commands that match the supplied pattern
historyprint the command history
jobslist information about jobs
killterminate the listed job
letevaluate an expression. Exit 0 if non-zero, 1 otherwise
localcreate variables local to the current function
logoutexit a login shell
popdremove entries from the directory stack
printfprint output like ANSI C printf
pushdadd an entry to the directory stack
pwdprint working directory name
readread stdin and assign values to a list of variables
readonlymark variables as read only
returnexit a function with a return value
setno args - display the environment variables with args - set flags and options
shiftrename positional parameters
shoptprint or change values of shell options
suspendsuspend current shell until a SIGCONT is received
[ testevaluate conditional expressions
timesprint accumulated process times
trapexecute a command if a specific signal is received
typedescribe how the shell interprets a name
ulimitset or print per-process limits
umaskset the creation permissions
unaliasremove an alias
unsetremove a variable
waitwait for a specific job.

III.b. External commands

All commands in a shell script that are not on the above list should be external commands. If you specify a complete directory path to the command, Bash will use that path. If you specify just the command, Bash will look in your $PATH list for the command.

III.c. Shell programming

By using a combination of the above built-in commands, external commands and Bash control commands, you can write shell scripts that will perform complex functions. The control commands allow you to control the script execution flow. Here is a list of control commands for Bash:

!execute a pipeline statement for Bash statement for Bash
func() {..}define a function
if..then..else..fiif statement for Bash statement for Bash
timeexecute a pipeline; print times on stderr statement for Bash statement for Bash
((..))arithmetic evaluation
[[..]]expression evaluation
(..)execute the list in a sub-shell
{..}execute the list in the current shell

The best way to descirbe how these commands are used is with examples. Here is a small script that prints the numbers from 0 to 9:

# Print numbers from 0 up to 9
for i in 0 1 2 3 4 5 6 7 8 9; do
echo $i

Note that the first line starts with a shebang (#!). This tells the shell which command interpreter to use to run the script. It could easily be perl or C shell instead of bash, but our script is a bash script.

The next line is a comment so we will remember what the script does.

Next is a program loop. The variable i is assigned each of the values in the list. When the list is exhausted, the loop ends. Inside the loop we echo the variable i to the console.

Here is another example which uses an 'if' statement:

# Make a backup of the fstab file, if it exists
if [[ -e /etc/fstab ]]; then
cp /etc/fstab /etc/fstab.bakup
echo "fstab backed up."
echo "fstab does not exist."

As a final example, here is how to process command line arguments:

# Check for a cmd line arg and echo it
if (( $# > 0 )); then
echo "Command line argument: $1";
echo "No command line argument present"

Note that the command line arguments are numbered $0, $1, $2, etc. The $0 argument contains the name of the script being run, so the first argument is $1. The $# variable contains the number of command line arguments.

This concludes the introduction to bash. If you want to learn more about the command shell, I suggest that you look for a tutorial on the Internet, or purchase "Learning the bash Shell", Second Edition By Cameron Newham and Bill Rosenblatt, published by O'Reilly.