█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/DevOps and Infrastructure/Linux and the Command Line/Shell Scripting
60 minIntermediate

Shell Scripting

After this lesson, you will be able to: Write bash scripts with variables, conditionals, loops, and functions to automate real tasks like backups, deploys, and log rotation.

Shell scripting is how ops engineers turn ad-hoc commands into repeatable automation. This lesson covers the syntax + the safety habits that prevent disasters.

Prerequisites:Networking from the CLI

Shebang + safety options (always)

Every production bash script starts with these. Memorise them.

tsx
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# Why each:
# -e exit on any error
# -u exit on undefined variable
# -o pipefail exit if any part of a pipe fails
# IFS prevent word-splitting bugs on filenames with spaces
# Without these, scripts silently swallow failures.

Variables, conditionals, loops, functions

Cover sheet of bash syntax.

tsx
name='alex' # no spaces around =
echo "Hello, $name"
echo "Date: $(date +%Y-%m-%d)"
# Conditional
if [[ -f /etc/passwd ]]; then
echo 'exists'
elif [[ -d /etc ]]; then
echo 'dir'
else
echo 'no'
fi
# String comparison: == ; numeric: -eq -lt -gt
if [[ "$1" == 'deploy' ]]; then ...
if (( count > 5 )); then ...
# Loops
for f in *.log; do echo "$f"; done
for i in {1..5}; do echo "$i"; done
while read -r line; do echo "$line"; done < input.txt
# Functions
backup() {
local src="$1"
local dest="$2"
tar -czf "$dest" "$src"
}
backup /var/www /backups/www-$(date +%F).tar.gz

A real deploy script

Drop this in /usr/local/bin/deploy.sh, chmod 755, run via cron or systemd timer.

bash
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
APP_DIR=/srv/myapp
REPO=https://github.com/me/myapp
LOG=/var/log/myapp/deploy.log
log() {
echo "[$(date '+%F %T')] $*" | tee -a "$LOG"
}
log 'Starting deploy'
cd "$APP_DIR"
log 'Pulling latest'
git fetch --all --quiet
git reset --hard origin/main
log 'Installing dependencies'
npm ci --omit=dev
log 'Building'
npm run build
log 'Restarting service'
sudo systemctl restart myapp
log 'Done'

Test and debug scripts

`bash -n script.sh`, syntax check without running. `bash -x script.sh`, print each command as it runs (debugger). `shellcheck script.sh`, static analysis catches 80% of bash bugs. INSTALL IT. Run scripts in a test directory before pointing at production. `set -x` inside the script turns on tracing; `set +x` turns it off.

💡 When bash is the wrong tool

Anything over ~100 lines, anything with complex data structures, anything that needs robust error handling, switch to Python. Bash shines at: gluing commands, simple iteration, file operations, shell wrapper for other tools. Bash struggles with: JSON, anything network-heavy, anything with lots of conditionals.

Common mistakes only experienced shell-scripters avoid

Skipping `set -euo pipefail`. Without it, errors silently propagate. Unquoted variables. `rm $FILE` with $FILE empty is `rm` (lists files); with a space, splits incorrectly. Always quote: `rm "$FILE"`. Trusting `cd` to succeed. `cd /nonexistent && rm -rf *` is a horror story without `set -e`. Using `eval`. Almost never necessary; almost always a security hole. Skipping shellcheck. It catches gotchas you wouldn't.

Quick Check

What's wrong with `cd /var/www && rm -rf *` if /var/www doesn't exist?

Pick the failure mode.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Networking from the CLI
Back to Linux and the Command Line
Environment and Configuration→