Skip to content

Shell Scripting Cheat Sheet

#!/usr/bin/env bash
set -euo pipefail # Exit on error, undefined var, pipe failure
FlagEffect
-eExit immediately on command failure
-uError on undefined variables
-o pipefailPipe fails if any command fails
-xPrint commands as executed (debug)
Terminal window
# Assignment (no spaces around =)
name="alice"
count=42
# Usage
echo "Hello, $name"
echo "Count: ${count}"
# Default values
${var:-default} # Use default if unset/empty
${var:=default} # Set and use default if unset/empty
${var:+alt} # Use alt if var IS set
${var:?error msg} # Exit with error if unset/empty

$() runs a command and substitutes its output. Use it to capture results into variables or embed output in strings.

Terminal window
# Assign output to a variable
current_branch=$(git branch --show-current)
# Embed in a string
tar czf "backup-$(date +%Y%m%d).tar.gz" ./src
# Capture output and check status
if output=$(git pull 2>&1); then
echo "Success: $output"
else
echo "Failed: $output"
fi
# Capture exit code
some_command
status=$?

See CLI Pipelines for $() used in pipeline composition — inline arguments, nesting, and fzf selection.

Terminal window
str="hello world"
${#str} # Length: 11
${str:0:5} # Substring: "hello"
${str:6} # From position: "world"
${str/world/there} # Replace first: "hello there"
${str//o/O} # Replace all: "hellO wOrld"
${str#hello } # Remove prefix: "world"
${str%world} # Remove suffix: "hello "
${str^^} # Uppercase: "HELLO WORLD"
${str,,} # Lowercase: "hello world"
Terminal window
# Declare
fruits=("apple" "banana" "cherry")
# Access
echo "${fruits[0]}" # First element
echo "${fruits[@]}" # All elements
echo "${#fruits[@]}" # Length
echo "${!fruits[@]}" # All indices
# Modify
fruits+=("date") # Append
fruits[1]="blueberry" # Replace
unset fruits[2] # Remove
# Iterate
for fruit in "${fruits[@]}"; do
echo "$fruit"
done
Terminal window
if [[ condition ]]; then
# commands
elif [[ condition ]]; then
# commands
else
# commands
fi

Strings:

OperatorMeaning
-z "$s"String is empty
-n "$s"String not empty
"$a" = "$b"Strings equal
"$a" != "$b"Strings differ
"$a" < "$b"Alphabetically less

Numbers:

OperatorMeaning
$a -eq $bEqual
$a -ne $bNot equal
$a -lt $bLess than
$a -le $bLess or equal
$a -gt $bGreater than
$a -ge $bGreater or equal

Files:

OperatorMeaning
-e fileExists
-f fileRegular file
-d fileDirectory
-r fileReadable
-w fileWritable
-x fileExecutable
-s fileSize > 0
f1 -nt f2f1 newer than f2

Logic:

Terminal window
[[ cond1 && cond2 ]] # AND
[[ cond1 || cond2 ]] # OR
[[ ! condition ]] # NOT
Terminal window
case "$input" in
start|begin)
echo "Starting..."
;;
stop|end)
echo "Stopping..."
;;
*)
echo "Unknown command"
;;
esac
Terminal window
# Over list
for item in apple banana cherry; do
echo "$item"
done
# Over array
for item in "${array[@]}"; do
echo "$item"
done
# C-style
for ((i=0; i<10; i++)); do
echo "$i"
done
# Over files
for file in *.txt; do
echo "$file"
done
# Over command output
for user in $(cut -d: -f1 /etc/passwd); do
echo "$user"
done
Terminal window
# Counter
count=0
while [[ $count -lt 5 ]]; do
echo "$count"
((count++))
done
# Read lines from file
while IFS= read -r line; do
echo "$line"
done < input.txt
# Read lines from command (see CLI Pipelines for process substitution)
while IFS= read -r line; do
echo "$line"
done < <(some_command)
Terminal window
break # Exit loop
continue # Skip to next iteration
Terminal window
# Definition
greet() {
local name="$1" # Local variable
local greeting="${2:-Hello}" # With default
echo "$greeting, $name!"
return 0 # Exit status
}
# Usage
greet "Alice" # "Hello, Alice!"
greet "Bob" "Hi" # "Hi, Bob!"
result=$(greet "Carol") # Capture output
VariableMeaning
$0Script name
$1-$9Positional arguments
$@All arguments (as array)
$*All arguments (as string)
$#Number of arguments
$?Last command exit status
$$Current script PID
Terminal window
# Basic
read -r name
echo "Hello, $name"
# With prompt
read -rp "Enter name: " name
# Silent (passwords)
read -rsp "Password: " pass
# With timeout
read -rt 5 -p "Quick! " answer
Terminal window
# Here document — multi-line input with variable expansion
cat <<EOF
Line 1
Line 2 with $variable expansion
EOF
# Quoted delimiter — suppress expansion
cat <<'EOF'
Line with $literal dollar signs
EOF
# Indented (<<- strips leading tabs)
if true; then
cat <<-EOF
indented body
EOF
fi
# Here string — single-line input
grep "error" <<< "$log_output"
bc <<< "2 ^ 10" # 1024
Terminal window
cmd > file # Stdout to file (overwrite)
cmd >> file # Stdout to file (append)
cmd 2> file # Stderr to file
cmd &> file # Both stdout and stderr
cmd 2>&1 # Stderr to stdout
cmd < file # File to stdin
cmd <<< "string" # String to stdin
Terminal window
# Check exit status
if ! command; then
echo "Command failed"
exit 1
fi
# Trap errors
trap 'echo "Error on line $LINENO"; exit 1' ERR
# Cleanup on exit
cleanup() {
rm -f "$tmpfile"
}
trap cleanup EXIT
# Custom error function
die() {
echo "Error: $*" >&2
exit 1
}
[[ -f "$file" ]] || die "File not found: $file"
Terminal window
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose)
verbose=true
shift
;;
-f|--file)
file="$2"
shift 2
;;
--)
shift
break
;;
-*)
die "Unknown option: $1"
;;
*)
args+=("$1")
shift
;;
esac
done
Terminal window
require() {
command -v "$1" >/dev/null 2>&1 || die "$1 required but not found"
}
require curl
require jq
Terminal window
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT
echo "data" > "$tmpfile"
Terminal window
spinner() {
local pid=$1
local chars="/-\|"
while kill -0 "$pid" 2>/dev/null; do
for ((i=0; i<${#chars}; i++)); do
printf "
%s" "${chars:$i:1}"
sleep 0.1
done
done
printf "
"
}
long_command &
spinner $!
  • CLI Pipelines — Pipes, xargs, fzf, process substitution, and composing commands into data streams
  • Cryptography — openssl commands for scripting
  • Regex — Pattern matching in scripts
  • Unix — Individual commands used in scripts