Bash Shell
There are often several different shells installed on a Linux system. bash
is
probably the most common, and is typically the default for new users on any
system. bash
is running in the terminal, and it interprets and executes the
commands we type in.
Environment
User Configuration
On startup, such as when a new terminal is opened, or you connect to a remote
system over the network, bash
will read several configuration files depending
on how it detects it is running.
- For login shells (shells where you are prompted to login when you start it),
bash
will read configuration options in~/.bash_profile
or~/.profile
if these exist. Note~
is interpreted by the shell as the users home directory. - For non-login shells (such as when you open the terminal emulator)
bash
will read configuration options in~/.bashrc
. - A lot of the time, for simplicity, many people will put all their
configuration options in
~/.bashrc
and leave their~/.profile
empty except for a command to read the~/.bashrc
file.
These files can be used to configure many aspects of the shell, such as how the prompt looks in the terminal.
Environment Variables
Many important aspects of how bash
behaves are governed by environment
variables. These can be modified to your preference in your configuration
files. To see the current value of one of these variables you can do, e.g.
echo $PATH
. A $
symbol is used when referring to the data stored in a
variable, and echo
is a built-in bash command that outputs something to the
terminal.
PATH
: this tells bash which directories to look in for executables so they can be run without typing in their full path. For example, we can just type ingedit
in the terminal to launch the program, as thePATH
variable contains the directory holding an executable of this name. Different directories are separated by “:”.- To add the directory
~/.bin
to your path, you can add the lineexport PATH="~/bin:$PATH"
to the.bashrc
file. Here theexport
statement is used to allow the variable to be usable by any child processes rather than local to the script. Note when we are naming the variable we want to assign a value to we don’t use a$
. Also we just want to add a directory to the existingPATH
so we add:$PATH
to keep all the existing directories.
- To add the directory
Scripting
Shell scripts allow you easily string together sets of commands in a useful way. For example, you could write a script that runs a calculation, parses the important results to another file, and then generates a plot.
This course will only be able to briefly cover scripting. If you’re interested in developing more advanced scripts, I strongly suggest referring to the Advanced Bash-Scripting Guide.
The basics
A simple example script to output “Hello World!” is as follows:
#!/bin/bash
# Simple example script that outputs "Hello World!"
echo "Hello World!"
- The first line tells the system what command is used to interpret the
contents of the script. This line should always begin with
#!
and then the path to the executable. Forbash
the executable will almost always be/bin/bash
. - Comments being with
#
. - Commands can be entered otherwise as you would enter them to the terminal.
- Try creating a file called
hello.sh
with the contents listed above. - You will need to make the script executable with
chmod u+x hello.sh
. - Then you can run it by typing
./hello.sh
.
Variables
Variables don’t need to be declared in any way, you can assign a value and start using them. For example:
#!/bin/bash
# Example using variables.
var1="Hello"
var2="World!"
echo $var1 $var2
# Note the use of the $ symbol when we want to use the value stored in the
# variable.
# Any command can use these variables
dirname="tmpdir"
mkdir $dirname
You can also read a value from stdin using the read
command as follows:
#!/bin/bash
# Example showing how the read command is used.
echo "Please enter some text:"
read user_text
echo "The text you entered was:" $user_text
Capitalization
Note: variable names are case sensitive in bash. The usual convention used is
that environment variables (such as PATH
), and internal shell variables
(such as BASH_VERSION
) are capitalized, while other variables are in
lowercase. Adopting this convention will ensure that you don’t accidentally
overwrite any important variables in your scripts.
Command Substitution
Command substitution allows the result of a command to replace the command itself, acting much like a variable in practice. For example:
#!/bin/bash
# Example of command substitution.
# This can be done by enclosing the command in $( )
echo "It is now $(date)."
# Note: the "date" command outputs the current date and time.
# This can also be done by enclosing the command in backtics ` `
echo "The files in this directory are:" `ls`
Conditional Statements
if
statements can be used in bash, and many types of tests are possible.
You can test if the value stored in a variable equals something as follows:
#!/bin/bash
# Example using if statatements
echo "Please enter a yes or no: "
read user_response
# Note the spaces following `[` and before `]` are important.
if [ $user_response = yes ]
then
echo "You entered yes."
elif [ $user_response = no ]
# "elif" is the same as "else if"
then
echo "You entered no."
else
echo "You didn't enter yes or no."
fi
# "if" statements are always ended with "fi".
We can also check, e.g., if a file or directory exists:
#!/bin/bash
# Check if the directory "tmpdir" exists, and if not, create it, then check
# if the file "tmpdir/testfile" exists, and if not, create it.
dirname="tmpdir"
filename="testfile"
if [ ! -d "$dirname" ]
# The "!" is logical negation
# -d tests that a file exists and is a directory.
then
mkdir $dirname
fi
if [ ! -f "$dirname/$filename" ]
# -d tests that a file exists and is a regular file (i.e. not a directory).
then
touch "$dirname/$filename"
fi
Many other tests of this form are possible.
Note, bash can also use the [[ ... ]]
test construction rather than
[ ... ]
, with the former offering some more options and functioning more like
other programming languages, though it won’t work in many other (non-bash, or
older bash version) shells.
Arithmetic and Testing
To test numeric values, the (( ... ))
construction can be used. For example:
#!/bin/bash
# Example showing the use of the (( )) construction
var1=4
var2=5
var3=8
if (( var1 + var2 > var3 ))
# Note within the (( )) don't use $ symbols before variables.
then
echo "$var1 + $var2 > $var3"
else
echo "$var1 + $var2 <= $var3"
fi
# We can also use the construction to perform basic arithmetic
var4=$(( var1 * var3 ))
echo "$var1 * $var3 = $var4"
For Loops
For loops iterate a variable over a range of values. For example:
#!/bin/bash
# Simple for loop example.
# This construction loops over a space separated list of values. A variable
# whose contents contains spaces would work in the same way.
for i in 1 2 3
do
echo "Iteration number $i"
done
A for loops can be used to apply a command repeatedly to a set of files. For example:
#!/bin/bash
# Example showing a simple for loop over a list of arguments used to convert
# a set of data files with comma separted columns to tab separated columns.
for csvfile in "$(ls *.csv)"
do
datfile="$(basename $csvfile .csv).dat"
# basename is a tool to strip the suffix from a file. Here we use it
# to construct a new filename with the .dat extenstion.
sed 's/,/\t/g' $csvfile > $datfile
done
Bash also supports numeric loop ranges using the syntax
{start..finish..increment)
. For example
#!/bin/bash
# Example of for loop with numeric increments
for i in {0..6..2}
do
echo "The value of i is $i"
done
While Loops
Bash also supports while loops, where a set of commands are repeated continuously while a given condition is true. For example:
#!/bin/bash
# Example of while loop in bash
counter=0
# Here -lt means less than
while [ $counter -lt 10 ]
do
echo $counter
counter=$((counter + 1))
done
It is often convenient to use while
loops to operate on every line of a file.
For example:
#!/bin/bash
# Example of while loop reading lines from a file
linenumber=0
while read line
do
linenumber=$((linenumber + 1))
echo "$linenumber: $line"
# This will prepend each line of a file with its line number.
done < test.txt
Arguments
We can also pass arguments to bash scripts from the command line. For example:
#!/bin/bash
# Example using command line arguments. Call this script with several
# arguments.
echo "The first argument is $1"
echo "The second argument is $2"
echo "The number of arguments is $#"
echo "The full list of arguments is $@"
We can loop over arguments using a for loop as follows:
#!/bin/bash
# Example using a for loop to iterate over command line arguments.
for arg in $@
do
echo $arg
done
Functions
We can also define functions in bash as we would in other languages. These allow sections of code to be reused as needed and can help make a script easier to follow.
A simple example is as follows:
#!/bin/bash
# Simple example of a function in a bash script
# First we define a function called "hello", that will output "Hello World!"
# when called.
hello() {
echo "Hello World!"
}
# To call the function, we just use its name.
# Note function names in the script will take precedence over executable names
# from the path in the script.
hello