Shell Scripts

Shell Scripts

Shell scripts are the duct tape and bailing wire of computer programming.

Shell Scripts

You can use them:

  • To automate repeated tasks
  • For jobs that require a lot of interaction with files
  • To set up the environment for big, complicated programs
  • When you need to stick a bunch of programs together into something useful
  • To add customizations to your environment

A practical example

runit1.sh

#!/bin/bash

fg++ *.cpp
./a.out

Variables

Make your own

#!/bin/bash

COW="big"

echo "$COW"

Special Variables

  • $? Exit code of the last command run
  • $0 Name of command that started this script (almost always the script’s name)
  • $1, $2, ..., $9 Comand line arguments 1-9
  • $@ All command line arguments except $0
  • $# The number of command line arguments in $#

Variable Gotchas

  • Bash really likes splitting things up into words.
  • for arg in $@ will NOT do what you expect.
  • for arg in "$@" correctly loops over args with spaces.
  • In general, when using the value of a variable you don’t control, it is wise to put "s around the variable.

A Spiffier Example

runit2.sh

#!/bin/bash

fg++ *.cpp -o "$1"
./"$1"

The value of $1 is entered by the user on the command line. We use " around it to make sure bash doesn't split it into words.

Conditions and Branching

Conditionals

if.sh

#!/bin/bash

# Emit the appropriate greeting for various people

if [[ $1 = "Jeff" ]]; then
    echo "Hi, Jeff"
elif [[ $1 == "Maggie" ]]; then
    echo "Hello, Maggie"
elif [[ $1 == *.txt ]]; then
    echo "You're a text file, $1"
elif [ "$1" = "Stallman" ]; then
    echo "FREEDOM!"
else
    echo "Who in blazes are you?"
fi

Conditional Operators

  • [ ] is shorthand for the test command.
  • [[ ]] is a bash keyword.
  • [ ] works on most shells, but [[ ]] is less confusing.
  • (( )) is another bash keyword. It does arithmetic.

Using [[ ]]

With Strings

  • = String equality OR pattern matching if the RHS is a pattern.
  • != String ineqaulity.
  • < The LHS sorts before the RHS.
  • > The LHS sorts after the RHS.
  • -z The string is empty (length is zero).
  • -n The string is not empty (e.g. [[ -n "$var" ]]).

Using [[ ]]

With Numbers

  • -eq Numeric equality (e.g. [[ 5 -eq 5 ]]).
  • -ne Numeric inequality.
  • -lt Less than
  • -gt Greater than
  • -le Less than or equal to
  • -ge Greater than or equal to

Using [[ ]]

With Files

  • -e True if the file exists (e.g. [[ -e story.txt ]])
  • -f True if the file is a regular file
  • -d True if the file is a directory

There are a lot more file operators that deal with even fancier stuff!

Using [[ ]]

With Boolean Logic

  • && Logical AND
  • || Logical OR
  • ! Logical NOT
  • You can use parentheses to group statements, too!

Using (( ))

  • This mostly works just like C++ arithmetic does.
  • ** does exponentiation
  • You can do ternaries! (( 3 < 5 ? 3 : 5 ))
  • You don’t need $ on the front of normal variables.
  • Shell Arithmetic Manual

Spiffy++

runit3.sh

#!/bin/bash

if (( $# > 0 )); then
    g++ *.cpp -o "$1"
    exe="$1"
else
    g++ *.cpp
    exe=a.out
fi

if [[ $? -eq 0 ]]; then
    ./"$exe"
fi

(Could you spiff it up even more with file checks?)

Case statements

#!/bin/bash
case $word in
    a)
        echo "a, literally"
        ;;
    b*)
        echo "Something that starts with b"
        ;;
    *c)
        echo "Something that ends with c"
        ;;
    *)
        echo "Everything else"
        ;;
esac

Looping

For Loops

#!/bin/bash

echo C-style:
for (( i=1; i < 9; i++ )); do
    echo $i;
done

echo BASH-style:
for file in *.sh; do
    echo $file
done

While Loops

#!/bin/bash

input=""
while [[ $input != "4" ]]; do
    echo "Please enter the random number: "
    read input
done

Functions

Functions

  • Functions don't take parameters between parentheses!
    • Access them with $1, $2, ...
    • Get the count with $#
  • Functions don't return anything!
    • The called function can't return stuff to the caller.

Functions

#!/bin/bash

compile_file() {
    INPUTFILE=$1
    OUTPUTFILE=$2

    fg++ -o "$OUTPUTFILE" "$INPUTFILE"
}

parrot These are "several arguments"

Miscellany

  • Escaping characters: use \ on \, `, $, ", ', #
  • pushd and popd create a stack of directories
    • dirs lists the stack of directories
    • Use these instead of cd in scripts
  • set -u gives an error if you try to use an unset variable.
  • set -x prints out commands as they are run.
  • help <command> gives you help with builtins.