Blog
4 min read

Bash Scripting for Beginners: Automate the Commands You Keep Typing

A bash script is a text file of terminal commands you can run in one go. How to write and run your first script, variables, arguments, if-statements and loops, the safety line every script should start with, and a real deploy script you can adapt.

If you find yourself typing the same five terminal commands every day, you can put them in a file and run them with one command. That file is a shell script, and the most common kind is a bash script.

(New to the terminal? Read the terminal for complete beginners first.)

Your first script

Create a file called hello.sh:

#!/usr/bin/env bash
echo "Hello! Today is $(date +%A)."

The first line — the shebang — tells the system to run this file with bash. Then make it executable and run it:

chmod +x hello.sh
./hello.sh

The ./ means "the file in this folder." (Linux file permissions explains chmod +x.)

Start every script with this line

#!/usr/bin/env bash
set -euo pipefail

By default bash keeps going after a command fails — which can be disastrous (imagine cd failing, then rm -rf * running in the wrong folder). This line makes the script safer:

  • -e — stop if any command fails.
  • -u — stop if you use a variable that was never set (catches typos).
  • -o pipefail — a failure in the middle of a | pipeline counts as a failure.

Variables

name="my-app"
echo "Deploying $name"
echo "Backup file: ${name}-backup.sql"

Rules that trip everyone up:

  • No spaces around =. name = "x" is an error.
  • Always quote variables: "$name". Without quotes, a value with spaces breaks into multiple words.
  • Capture a command's output with $(...): today=$(date +%F).

Environment variables work the same way: echo "$HOME". (Environment variables explained)

Arguments

Values passed to the script are $1, $2, …; $@ is all of them.

#!/usr/bin/env bash
set -euo pipefail
env="${1:-staging}"     # first argument, default "staging"
echo "Deploying to $env"
./deploy.sh production

If-statements

if [[ -f .env ]]; then
  echo ".env exists"
else
  echo "Missing .env" >&2
  exit 1
fi

Handy tests:

Test True when
-f file File exists
-d dir Folder exists
-z "$var" Variable is empty
"$a" == "$b" Strings are equal
$n -gt 5 Number greater than 5

exit 1 stops the script with a failure code; >&2 sends the message to the error output.

You can also branch on whether a command succeeded:

if ! command -v node >/dev/null; then
  echo "Node.js is not installed" >&2
  exit 1
fi

Loops

for file in backups/*.sql; do
  echo "Found $file"
done

Functions

log() { echo "[$(date +%T)] $*"; }

log "Starting deploy"

A real example: a simple deploy script

#!/usr/bin/env bash
set -euo pipefail

cd "$(dirname "$0")"          # run from the script's own folder

log() { echo "[$(date +%T)] $*"; }

log "Pulling latest code"
git pull --ff-only

log "Installing dependencies"
npm ci

log "Running migrations"
npm run migrate

log "Building"
npm run build

log "Restarting"
pm2 reload my-app

log "Done"

Because of set -e, if the build fails, the restart never happens — your old version keeps running.

Debugging a script

Run it with bash -x script.sh to print each command before it runs. And install ShellCheck (brew install shellcheck, or the VS Code extension): it catches the quoting mistakes and gotchas that bite everyone.

Bash, sh, zsh, PowerShell?

  • bash — the default on most Linux servers. Scripts you'll deploy should target it.
  • zsh — the default interactive shell on macOS. Runs most bash scripts fine, but use the bash shebang anyway.
  • sh — a more minimal shell; some features above (like [[ ]]) aren't available.
  • PowerShell — Windows' shell, different syntax. Use WSL to run bash on Windows. (What is WSL?)

The summary

  • A script is a file of commands with #!/usr/bin/env bash on top.
  • Always add set -euo pipefail.
  • No spaces around =, and quote your variables.
  • $1 for arguments, [[ ]] for tests, for for loops.
  • bash -x and ShellCheck find most problems.

EasySpawn gives you a persistent Linux server with a real terminal, where your scripts — and Claude Code — can run on a schedule or on demand. See how it works or join the waitlist.

Related: The Terminal for Complete Beginners · Cron Expressions Explained · What Is Linux? · The PATH Variable and "Command Not Found"

Keep reading