Bash Scripting

Resources

Here are some useful guides and cheat sheets on Bash scripting:

Variables

Declare a variable with the name of the variable, an equal sign, and then the value of the variable within double quotes. Do not insert spaces:

name="Sean"
backup="/media/"
# test it out:
echo "$name"
echo "$backup"
cd "$backup"
cd

Variables may include values that may change given some context. For example, if we want a variable to refer to today's day of week, we can use command substitution, which "allows the output of a command to replace the command name" (see man bash). Thus, the output at the time this variable is set will differ if it is set on a different day.

today="$(date +%A)"
echo "$today"

We can print the variable a number of ways. We can call it with a dollar sign and the name of the variable:

echo $today

But it's safer to wrap the variable in double quotes:

echo "$today"

A useful and safe way to print or refer to a variable, is to use the dollar sign plus the variable name and surround these in curly braces and quotations:

echo "${name}"
echo "${backup}"
echo "${today}"

The curly braces are not strictly necessary, but they offer benefits when we start to use things like array variables. See:

For example, let's look at basic brace expansion, which can be used to generate arbitrary strings:

echo {1..5}
echo {5..1}
echo {a..l}
echo {l..a}

Another example: generating two sub-directories. Start off in your home directory, and:

mkdir -p documents/{drafts,notes}

But more than that, they allow us to deal with arrays (or lists):

seasons=(winter spring summer fall)
echo "${seasons[1]}"
echo "${seasons[2]}"
echo "${seasons[-1]}"

See Parameter expansions for more advanced techniques.

Conditional Expression

We can include a list of commands on one line in Bash with a semicolon:

cd ; ls -lt

But we can use conditional expressions and apply logic with && (Logical AND) or || (Logical OR).

Here, command2 is executed if and only if command1 is successful:

command1 && command2

Here, command2 is executed if and only if command1 fails:

command1 || command2

Example:

cd documents && echo "success"
cd documents || echo "failed"
# combine them:
cd test && pwd || echo "no such directory"
mkdir test
cd test && pwd || echo "no such directory"

Shebang or Hashbang

When we start to write scripts, the first thing we add is a [shebang][shebang] at line one. We can do so a couple of ways:

##!/usr/bin/env bash

The first one should be more portable, but alternatively, you could put the direct path to Bash:

#!/usr/bin/bash

Looping

There are several looping methods Bash, including: for, while, until, and select. The for loop is often very useful.

for i in {1..5} ; do
  echo "$i"
done

With that, we can create a rudimentary timer:

for i in {1..5} ; do
  echo "$i" ; sleep 1
done

We can loop through our seasons variable:

for i in ${seasons[@]} ; do
  echo "$i"
done

Testing

Sometimes we will want to test certain conditions. There are two parts to this, we can use if; then ; else commands, and we can also use the double square brackets: [[. There are a few ways to get documentation on these functions. See the following:

man test
help test
help [
help [[
help if

We can test integers:

if [[ 5 -ge 3 ]] ; then
  echo "true"
else
  echo "false"
fi

Reverse it to return the else statement:

if [[ 3 -ge 5 ]] ; then
  echo "true"
else
  echo "false"
fi

We can test strings:

if [[ "$HOME" = "$PWD" ]] ; then
 echo "you are home"
else
 echo "you are not home, but I will take you there"
 cd $HOME
 pwd
fi

We can test files. Let's first create a file called paper.txt and a file called paper.bak. We will add some trivial content to paper.txt but not to the second file. The following if statement will test if paper.txt has a more recent modification date, and if so, it'll back up the file with the cp and echo back its success:

if [[ "$HOME/paper.txt" -nt "$HOME/paper.bak" ]] ; then
  cp "$HOME/paper.txt" "$HOME/paper.bak" && echo "Paper is backed up."
fi

Here's a script that does prints info depending on which day of the week it is:

day1="Tue"
day2="Thu"
day3="$(date +%a)"

if [[ "$day3" = "$day1" ]] ; then
  printf "\nIf %s is %s, then class is at 9:30am.\n" "$day3" "$day1"
elif [[ "$day3" = "$day2" ]] ; then
  printf "\nIf %s is %s, then class is at 9:30am.\n" "$day3" "$day2"
else
  printf "\nThere is no class today."
fi

Summary

In this demo, we learned about:

  • creating and referring to variables
  • conditional expressions with && and ||
  • adding the shebang or hashbang at the beginning of a script
  • looping with the for statement
  • testing with the if statement

These are the basics. I'll cover more practical examples in upcoming demos, but note that mastering the basics requires understanding a lot of the commands that we have covered so far in class. So keep practicing.