AR

Shell Programming (Bash) – CMPSC 311 Study Notes

Overview of Shell Programming

  • Terminology
    • Also called “shell scripting” or “Bash scripting”
    • Consists of writing a series of commands that are executed by a shell interpreter
  • Primary purposes
    • Automation of repetitive tasks
    • System administration (user management, backups, monitoring, etc.)
    • Rapid prototyping / glue code that links together existing programs

Basic Script Structure

  • Interpreter (she-bang) line must be the first line
    • Example: #! /bin/bash
    • Tells the kernel which program should interpret the file
  • Comments begin with # and continue to end-of-line
  • File needs execute permission; extension .sh is conventional but not required
    • Give permission with chmod +x scriptname
  • Running a script
    • From current directory: ./shello

Sample script: shello

#! /bin/bash      # Greetings!
echo Shello world             # literal output
echo Shello "$USER"       # uses special variable

# Set and use a new variable
greetz=Shellutations
echo "$greetz world"

Shell Variables

  • Creation / assignment (no spaces): var=value
  • Export to environment: export var=value
  • Remove variable: unset var
  • Use value with $ prefix: $var
  • Untyped by default – treated as strings unless used in arithmetic context (see help declare)

Special Built-in Variables

  • PWD – present working directory
  • USER – current user’s login name
  • HOME – home directory, often abbreviated ~
  • PATH – colon-separated list of directories searched for executables
  • PS1 – primary prompt string (customizable)

PATH Exercise

  • 1️⃣ Create personal bin directory: mkdir -p ~/bin
  • 2️⃣ Move shello there: mv shello ~/bin
  • 3️⃣ Prepend directory to path: PATH=~/bin:$PATH
  • 4️⃣ Change to home (cd) and simply type shello to execute (shell finds it via new PATH)

Shell Initialization

  • Bash executes ~/.bashrc for interactive, non-login shells
    • File is just another shell script – can set aliases, functions, variables, prompt, etc.

Prompt Customization (Fun with $PS1)

  • Escape sequences (partial list)
    • \u – username
    • \h – hostname (up to first dot)
    • \w – current working directory (with ~ substitution)
    • \e – literal escape (used for colors)
  • Detailed guide: http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/
  • Example custom prompt: PS1="[\u@\h \w $?]$ " (includes last exit status)

Special Characters & Quoting

  • Characters with special meaning: whitespace, #$*&^?!~'\"{}[]<>()|;`
  • Quoting methods
    • Hard quotes '…' – everything literal except closing '
    • Soft quotes "…" – allow variable substitution & some escapes; best practice: quote variables as "$var"
    • Backslash \ – escapes next single character
  • Examples
    • echo Penn State is #1#1 starts a comment, prints “Penn State is” only
    • To print literally: echo "Penn State is #1"

Script & Command Arguments

  • In C: argc, argv[]; in shell:
    • $# – number of arguments (≈ argc)
    • $@ – all arguments as separate quoted words
    • $1 … $9 – first nine individual arguments
  • Running a script: ./script foo bar
  • Override default whitespace splitting? Use quoting or IFS variable

Debug Mode

  • bash -x script – traces execution: prints each command after expansion, arguments quoted
  • bash -xv – additionally prints input lines as they are read (v = verbose)
  • Temporary; does not modify script

Redirection & Pipelines

  • Redirect stdout
    • Overwrite: echo hello > world
    • Append: echo hello >> world
  • Redirect stdin
    • tr h j < world
  • Combine multiple programs with pipelines |
    • Example: echo hello | tr h j | rev | hexdump -C | grep 06
    • Embodies UNIX philosophy: each program does one thing well; combine them.

Exit Status & Return Codes

  • In C, main returns an int; same integer becomes process’s exit status
    • Convention: 0 = success, non-zero = error/failure/signal
  • Retrieve in shell with $?
  • Example C program status.c:
  #include <stdlib.h>
  int main(int argc, char **argv) { return atoi(argv[1]); }

Usage: ./status 2 ; echo $? prints 2.

Custom prompt containing exit status

  • Include $? in PS1 to show last command’s status live

Exit status inside scripts

  • $? gets last command’s status
  • Script’s own exit status = exit status of last command unless exit n used explicitly
  • ! cmd – logical NOT; succeeds (exit 0) when cmd fails and vice-versa

Conditionals

  • Basic form
  if list ; then
      cmds
  elif list2 ; then
      cmds2
  else
      cmds3
  fi
  • list is executed; if it ends with status 0, the then branch runs

Test Built-ins

  • true – always returns 0
  • false – always returns 1
  • Generic test syntax: test condition or shorthand [[ condition ]]
    • Returns 0 if test is true, 1 otherwise
Common Test Options
  • File tests
    • test -e file – file exists
    • test -d dir – directory exists
  • String tests
    • test -z "$var" – variable length 0 (empty)
    • test -n "$var" – variable non-empty
    • test str1 = str2 – strings equal
  • Numeric tests
    • test num1 -gt num2 (greater than)
    • Other operators: -lt, -ge, -le, -eq, -ne

Shorthand [[ … ]]

  • More modern, avoids many quoting hassles
  • Example: [[ $age -ge 16 ]] && echo can drive
  • Negation: ! [[ … ]]

Command Lists & Short-Circuiting

  • Sequential: cmd1 ; cmd2 – run both regardless of status
  • AND list: cmd1 && cmd2 – stop if cmd1 fails
  • OR list: cmd1 || cmd2 – run cmd2 only if cmd1 fails
  • Sample play-through (expectation):
    • true && echo one → prints one
    • true || echo two → prints nothing
    • false && echo three → prints nothing
    • false || echo four → prints four
    • test -e Makefile && make → build only if Makefile exists

Loops

  • while loop (runs while list succeeds):
  while list ; do
      cmds
  done
  • until loop (opposite: continues while list fails)
  • Example from slides:
  while [[ "$x" -lt 99999 ]]; do
      echo "$x"
      x="1$x"
  done

Command Substitution

  • Replaces $(command) (modern) or `command` (legacy) with command’s stdout (minus trailing newline)
  • Example: file $(which ls) – runs which ls, inserts its output into file command

For Loops (for-each)

  • Syntax
  for var in word1 word2 … ; do
      cmds
  done
  • Example ranges
    • for i in $(seq 1 5); do echo $i; done
    • for i in {1..5}; do echo $i; done (brace expansion)
  • Other examples
    • Triple each argument:
      bash for a in A B C hello 4; do echo "$a$a$a" ; done
    • Process headings by extension:
      bash for ext in h c; do cat "hello.$ext" ; done

Filename Globbing (Wildcards)

  • * (asterisk) – zero or more characters
    • echo *.c – list all .c files
  • ? – exactly one character
    • echo hello.? – hello.a, hello.b, etc.
  • Typical use with loops for bulk renaming:
  for f in hello.* ; do mv "$f" "$f.bak" ; done

Handy One-Liner Tools

  • touch foo – create file if missing or update timestamp
  • sleep t – pause for t seconds
  • grep -F string – filter stdin for lines containing string (fixed string search)
  • find . -name '*.c' – recursively list .c files; many predicates (permissions, size, mtime, etc.)
  • file foo – identify file type
  • wc – count lines / words / bytes
  • bc – arbitrary-precision calculator (reads from stdin)

Exercises & Practice Ideas

  • Print “foo” every second until user presses Ctrl-C (signal SIGINT):
  while true ; do
      echo foo
      sleep 1
  done
  • Find all .png files under dir/:
  find dir -name '*.png'
  • Find all files in dir/ whose actual content is PNG: (check magic number)
  find dir -type f -exec file {} \; | grep 'PNG image'
  • Compute product 199 \times 42 via pipeline & bc:
  echo '199*42' | bc
  • Script 1 (double first argument):
  #! /bin/bash
  printf '%s%s\n' "$1" "$1"
  • Script 2 (first four args in brackets, one per line):
  #! /bin/bash
  for n in 1 2 3 4 ; do
      eval arg=\${$n:-}
      echo "[${arg}]"
  done

References for Further Mastery

  • Advanced Bash-Scripting Guide: http://tldp.org/LDP/abs/html/
  • commandlinefu.com – collection of clever one-liners; good for reverse engineering practice
  • man bash – authoritative manual (options, built-ins, grammar, etc.)

Process Control & Safety Tip

  • If a script or command misbehaves (infinite loop, runaway process) use Ctrl-C (SIGINT) to terminate; appears as ^C on terminal.