Introduction To BASH

Here we'll cover what BASH is, some basic BASH usage, and point you toward what you need to learn to configure BASH and customise the prompt.

What Is BASH

BASH is a shell (The name stands for Bourne Again Shell which refers to one of its predecessors, the Bourne Shell). A shell is the software which parses the commands and instructions that you enter at the prompt of your terminal or virtual console, then runs them on your behalf.

How Does BASH Know About Commands/Programs/Utilities?

BASH determines the existence of commands you type by searching for them in your "PATH" environment variable (more about this later). If you enter the command:

echo $PATH
or
printenv PATH
This will show you exactly what paths are searched for what's available on your system.
A default example of what PATH holds might look like this:
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
As you can see, each of the paths is delimited (separated) by a colon.
So with a PATH variable like this one, when you run a command the first place the shell checks for the existence of the command is "/usr/local/sbin". If its not found there, then it checks "/usr/local/bin" and so on.
You can add paths to your PATH variable by editing ~/.profile.
Find this line:
PATH="$HOME/bin:$PATH"
and add your extra path to the end of this string e.g. /usr/extra/path,
PATH="$HOME/bin:$PATH:/usr/extra/path"
New shells will now get the new PATH, but pick up the new PATH in your current shell, you'll then need to run:
source ~/.profile
There's more on the topic of configuring bash in the next section.
Note that if you do add your own changes to the PATH variable, its considered good practice not to put a "." (current directory) on the list of paths to search, especially if its for root's PATH. And for users other than root, if you must put a "." in the path, put it last so that the normal command locations are searched before the current directory.

Configuring BASH

We cover configuring bash in more detail here, but for now we'll just mention that the files ~/.profile and ~/.bashrc can be used to configure your shell (The first is run at initial login, the second is run when a new instance of /bin/bash is started).

Environment Variables

Environment variables are one of the ways in which BASH and the programs that it runs for you are configured. To get a feel for what sort of variables exist, you can dump of all the environment variables by running:

printenv
We'll discuss environment variables that affect specific programs in their relevant posts. For now the main ones to know about are: PATH (which we mention above) and PS1 which is used for customising the command prompt which we'll point you toward below.

Customising The Command Prompt

If you'd like to tweak the shell prompt displayed in your terminal, you'll need to change the PS1 environment variable.
For example, you may wish to include the date and time in the prompt.
In Ubuntu, the PS1 variable is set in your ~/.bashrc file. To take a look at what it end up as, run:

echo $PS1
You should see something like:
\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$
So to add the date and time (without seconds. If you also want seconds, just stick :%S after the %M into the string below) to the current shell you need to add the sub string:
\D{%Y-%m-%d %H:%M}
To add it temporarily, i.e. without affecting future bash shell instances, you could run the following:
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h: \D{%Y-%m-%d %H:%M}:\w\$ '
Note that using single quotes is important here otherwise the string you set will be interpreted by the shell before being set, thus setting a string other than what you intend!
To change it permanently, you would need to add the substring to your PS1 variable in ~/.bashrc file.
We'll cover customising this prompt and others in more detail in a future post.

External Commands vs Built-in Commands

Some commands are build into BASH itself (i.e. are part of BASH) and others are external commands. To find out whether a command is built in or not you can use "type". e.g:

type pwd
Tells us that pwd is built into bash, whereas:
type ls
tells us that ls is aliased to `ls --color=auto' while adding a "-a":
type -a ls
tells us that the underlying ls is an external command /bin/ls.
Note that some commands will have a built-in and an external version of the command.

BASH Keyboard Shortcuts

To help you become more productive when using the command line, please refer to the list of bash shortcuts in this post.

Introduction To Standard Input,Output, And Error

Linux sends all output to a file. Even the screen (where your shell prompt is) is considered a file.
Unless a program or command redirects output, it is send to a special file called "standard output". By default, this represented by the screen.
Similarly, errors from a program are sent to "standard error" which by default is also represented by the screen.
The symbol "&1" can be used to represent standard output, while "&2" represents standard error.
There is also an "&0" which represents standard input.
So you can consider &1 and &2 as locations where you can send data, while &0 is a location you can get data from.
As you'll see shortly, you can redirect standard input and output to places other than these and even make the data vanish if need be.

Storing Command/Program Results To File

You can redirect data output from a command into a file by using the ">" redirection operator. For example to store the result of ls -la into a file called out.txt, you could use:

ls -la > out.txt
Note that if the file out.txt does not exist, it will be created. If it does exist it will be overwritten (clobbered).
If you'd like to append the output from a command to a file if it already exists (rather that clobber the file), you can use the append redirection operator ">>", for example:
ls -la >> out.txt

Redirecting Command Output and Errors to specific places

You can explicitly redirect output by using "1>" for example:

ls -la 1> output.txt
Similarly, you can redirect errors by using "2>" for example:
ls -la no_such_file.txt 2> error.txt
These can be combined so any errors get sent to one file while normal output gets send to another file. For example, this command will find all files with the extension .conf that live under the /etc directory, putting any errors into error.txt while putting normal output (the results) into results.txt:
find /etc/ -name "*.conf" 2>error.txt 1>result.txt
If you need to append to the files rather than replace them for each run, you could use:
some_command 2>>error.txt 1>>result.txt
where some_command can be replaced by whatever command you need to run. To send both standard output and error to the same file, you can use one of ">&" or "&>", for example:
find /etc/ -name "*.conf" &> output.txt
another way yet again (perhaps more readable) would be:
find /etc/ -name "*.conf" > output.txt 2>&1
where we basically just redirect standard output using ">", and then send errors to the location of standard output (remember &1 mentioned earlier?) which we've set to be output.txt.

Redirecting Command Output to Other Commands

When you would like to send the output from one command to the input of another, you can use the pipe operator "|". For example, to count the number of lines in a file called file.txt, you could use:

cat file.txt | wc -l
You can pipe many commands together, e.g. running this contrived example:
cat file.txt | tail -n 100 | less
will pass the last 100 lines from the file file.txt to the less command so you can easily scroll up and down the resulting lines.

Redirecting Output and/or Errors to Nowhere

You can send any sort of data to the special file /dev/null, which is like a black hole, so the data ends up disappearing forever.
If there's a command that produces output or errors that you're not interested in seeing, just send the data to /dev/null and it will not get displayed anywhere. For example, to send error messages to /dev/null, use:

some_command 2> /dev/null
(where some_command is whatever command you need to run).

Directing Output to More than One place

If you need to display or save output to file and also send that output to another command at the same time, you can use the "tee" command.
For example the below line will save the output from some_command into save.txt, while still sending the output to grep to search for lines containing "something", then counting the number of lines found:

some_command | tee save.txt | grep "something" | wc -l

Hidden Files

Had you noticed that doing an ls on your home directory doesn't show any files that begin with a dot such as .bashrc or .profile ?
This is because such files are hidden by default. They are normally some sort of configuration file, so are kept out of the results shown by ls unless you use the "-a" or "--all" option. Hence running:

ls -la
will show such files.
Note that using hidden files such as these are just to help keep your directories free from clutter and are nothing to do with security!

BASH Scripting

Putting one or more commands that perform a specific job/task into a file for future use is pretty common.
Such a file can be referred to as a bash script, and would have the extension ".sh", so myjob.sh could be an example of what you might call such a script. Bash also provides looping and control structures for your use, much in the same way as a conventional programming language. Hence bash scripting can be considered as being in the category of programming.
BASH scripting is beyond the scope of this post, but we shall be covering the topic at some stage in the future.

Thanks to Brian Fox and Chet Ramey for implementing BASH.