Intro to Shell Scripting
Computer Science 4

Introduction

Shell scripts are a useful tool for automating repetitive or complex tasks. This module will teach the development of Bash scripts.

Tutorial

Here is a tutorial on Bash scripting that I reference often for learning various I need for tasks I'm working on. This provides an interesting background for regular expressions and how they work.

Examples

The following scripts use git commands to manipulate a repository's history. The second uses the plumbing command for-each-ref to enumerate all local branches.

loc-generate.sh (Checks out each commit in a Git repository's history and generates a CSV file of number of lines of code in the repository)

#!/bin/bash

git checkout -q master
read -r -a array > data.csv
  else
    echo $x$','$y','$x$','$y >> data.csv
  fi
done

# Print newline so prompt appears on next line
echo
    

mirror.sh (Used for management of 20+ branches in allwpilib Git repository)

#!/bin/bash

# ./mirror.sh COMMAND STARTBRANCH
# 1st argument is command to run
# 2nd argument is starting branch

if [ $# -eq 0 ]; then
  exit 1
fi

# If a starting branch was provided, don't run until that branch is checked out
if [ $# -eq 2 ]; then
  run=false
else
  run=true
fi

if [ "$1" == "rebase" ]; then
  git checkout -q master
  git pull -q upstream master
fi

branches=()
eval "$(git for-each-ref --shell --format='branches+=(%(refname))' refs/heads/)"
for branch in "${branches[@]}"; do
  base=$(basename $branch)
  if [ "$run" = false ]; then
    if [ "$base" == "$2" ]; then
      run=true
    fi
  fi

  if [ "$run" = true ]; then
    echo "Switching to branch '$base'"
    git reset -q --hard HEAD
    git checkout -q $base

    # Run subcommand
    case $1 in
    "build")
      if [ "$base" == "itable-base" ] ||
         [ "$base" == "kalman-filter" ] ||
         [ "$base" == "master" ] ||
         [ "$base" == "motion-profile" ] ||
         [ "$base" == "pid-dt" ]; then
        continue
      fi

      git apply allwpilib-gradle.patch

      ./gradlew build
      ;;
    "buildsim")
      if [ "$base" == "itable-base" ] ||
         [ "$base" == "kalman-filter" ] ||
         [ "$base" == "master" ] ||
         [ "$base" == "motion-profile" ] ||
         [ "$base" == "pid-dt" ]; then
        continue
      fi

      git apply allwpilib-gradle.patch

      ./gradlew build -PmakeSim
      ;;
    "format")
      ./styleguide/format.py
      ./license-update.py
      if [ `git diff | wc -l` != "0" ]; then
        echo "branch '$base' modified by format.py"
        exit 1
      fi
      ;;
    "push")
      git push -f
      ;;
    "rebase")
      if [ "$base" != "cap-sys-nice" ] &&
         [ "$base" != "cleanup-command" ] &&
         [ "$base" != "cleanup-const" ] &&
         [ "$base" != "getinstance" ] &&
         [ "$base" != "itable-base" ] &&
         [ "$base" != "motor-safety-base" ] &&
         [ "$base" != "pid-filter" ]; then
        git rebase master
      fi
      ;;
    "setorigin")
      git branch --set-upstream-to origin/$base
      ;;
    *)
      echo '$1' not a valid subcommand
      exit 1
      ;;
    esac

    if [ $? -ne 0 ]; then
      exit 1
    fi
  fi
done