Atuin cheatsheet: Ctrl-R search keys, filter and search modes, non-interactive flags, sync and …
Bash Basics Cheatsheet Bash Basics Cheatsheet

Summary
I write Bash almost every day (deploy scripts, CI glue, one-off automation) and I still forget the exact parameter expansion syntax more often than I’d like to admit. This is the page I keep open: the Bash 5.x bits I actually use, condensed. For text-wrangling inside scripts, see my Bash sed & awk Cheatsheet.
Shebang & Safe Defaults
Start every script with this:
Expand your knowledge with Ansible Cheatsheet
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
| Option | Effect |
|---|---|
set -e | Exit immediately on any command failure |
set -u | Error on unset variables (catches typos) |
set -o pipefail | A pipeline fails if any stage fails, not just the last |
set -x | Print each command before running (debug mode) |
bash -x script.sh # debug an existing script without editing it
set +e # temporarily allow failures
some_flaky_command || true # tolerate a single failing command under set -e
Variables & Quoting
Docs: Quoting, GNU Bash manual
Deepen your understanding in Ansible Cheatsheet
name="karandeep" # no spaces around =
readonly REGION="ca-central-1"
export PATH="$PATH:/opt/bin"
unset name
echo "$name" # double quotes expand variables; use by default
echo '$name' # single quotes: literal, no expansion
echo "${name}_backup" # braces to delimit the variable name
rm -rf "$dir/". Left unquoted, an empty or space-containing $dir can wipe the wrong path. shellcheck will catch most of these; run it on every script.Parameter Expansion
Docs: Shell Parameter Expansion, GNU Bash manual
Explore this further in Jenkins Cheatsheet
| Expansion | Meaning |
|---|---|
${var:-default} | Use default if var is unset or empty |
${var:=default} | Assign default to var if unset or empty |
${var:?message} | Exit with message if var is unset or empty |
${var:+alt} | Use alt only if var IS set |
${#var} | Length of var |
${var#pattern} | Remove shortest match from the front |
${var##pattern} | Remove longest match from the front |
${var%pattern} | Remove shortest match from the end |
${var%%pattern} | Remove longest match from the end |
${var/a/b} | Replace first a with b |
${var//a/b} | Replace all a with b |
${var^^} / ${var,,} | Uppercase / lowercase |
${var:2:5} | Substring: offset 2, length 5 |
file="app.tar.gz"
echo "${file%%.*}" # app (strip longest from end-matching .*)
echo "${file%.*}" # app.tar (strip shortest)
echo "${file#*.}" # tar.gz
path="/var/log/nginx/access.log"
echo "${path##*/}" # access.log (basename)
echo "${path%/*}" # /var/log/nginx (dirname)
env="${DEPLOY_ENV:?DEPLOY_ENV must be set}"
Conditionals & [[ ]] Test Operators
if [[ -f "$config" && "$env" == "prod" ]]; then
echo "prod config found"
elif [[ "$env" =~ ^(dev|stage)$ ]]; then
echo "non-prod"
else
echo "unknown env" >&2
exit 1
fi
| Operator | True if… |
|---|---|
-f file | Regular file exists |
-d dir | Directory exists |
-e path | Path exists (any type) |
-r / -w / -x | Readable / writable / executable |
-s file | File exists and is non-empty |
-z str | String is empty |
-n str | String is non-empty |
str1 == str2 | Strings equal (glob match if unquoted RHS) |
str =~ regex | Regex match (capture groups in BASH_REMATCH) |
n1 -eq n2 | Integers equal (-ne -lt -le -gt -ge) |
f1 -nt f2 | f1 newer than f2 |
Use [[ ]] over [ ]: no word splitting, and it supports &&, ||, =~, and glob matching.
Discover related concepts in Go (Golang) Cheatsheet
Loops
Docs: Looping Constructs, GNU Bash manual
Uncover more details in Bash sed & awk Cheatsheet
for f in /etc/*.conf; do echo "$f"; done # glob loop
for i in {1..5}; do echo "attempt $i"; done # brace range
for ((i = 0; i < 10; i++)); do echo "$i"; done # C-style
while read -r line; do # read a file safely
echo "line: $line"
done < servers.txt
until curl -sf http://localhost:8080/health; do # wait for a service
sleep 2
done
while true; do date; sleep 5; done # poll loop
break; continue # work as expected
Functions
deploy() {
local env="$1" # local keeps vars scoped
local version="${2:-latest}" # default for optional args
echo "deploying $version to $env"
return 0 # numeric status only; echo for data
}
deploy prod v1.2.3
result="$(deploy stage)" # capture output via command substitution
$1..$9 ${10} positional args, $# count, $@ all args (quote it: "$@"), $0 script name, $FUNCNAME current function.
Journey deeper into this topic with AWS CloudFormation Cheatsheet
Arrays & Associative Arrays
Docs: Arrays, GNU Bash manual
Enrich your learning with Bash sed & awk Cheatsheet
hosts=("web1" "web2" "db1")
hosts+=("cache1") # append
echo "${hosts[0]}" # first element
echo "${hosts[@]}" # all elements
echo "${#hosts[@]}" # length
echo "${hosts[@]:1:2}" # slice: web2 db1
for h in "${hosts[@]}"; do ssh "$h" uptime; done
declare -A ports=([http]=80 [https]=443 [ssh]=22)
ports[dns]=53
echo "${ports[https]}" # 443
for k in "${!ports[@]}"; do echo "$k -> ${ports[$k]}"; done
mapfile -t lines < servers.txt # file into array, one line per element
Exit Codes
Docs: Exit Status, GNU Bash manual
Gain comprehensive insights from Kubernetes Cheatsheet
somecommand
echo "$?" # status of last command: 0 = success
grep -q "ERROR" app.log && echo "errors found"
systemctl is-active nginx || systemctl start nginx
command -v jq >/dev/null || { echo "jq required" >&2; exit 127; }
| Code | Convention |
|---|---|
0 | Success |
1 | General error |
2 | Misuse of builtin / bad usage |
126 | Found but not executable |
127 | Command not found |
130 | Killed by Ctrl-C (SIGINT) |
Traps
tmpdir="$(mktemp -d)"
cleanup() { rm -rf "$tmpdir"; }
trap cleanup EXIT # runs on any exit, even set -e
trap 'echo "failed at line $LINENO" >&2' ERR
trap 'echo "interrupted"; exit 130' INT TERM
EXIT is the workhorse: temp files, lock files, and spawned background jobs all get cleaned up no matter how the script dies.
Master this concept through Bash CLI One-Liners Cheatsheet
Here-Docs & Here-Strings
Docs: Redirections, GNU Bash manual
Delve into specifics at Bash sed & awk Cheatsheet
cat <<EOF > /etc/myapp/config.yaml
env: $DEPLOY_ENV
region: ca-central-1
EOF
cat <<'EOF' # quoted delimiter: NO expansion
literal $HOME stays as-is
EOF
sudo tee /etc/motd <<EOF >/dev/null
Managed by automation. Do not edit.
EOF
grep "prod" <<< "$config_text" # here-string: feed a variable to stdin
Command Substitution & Arithmetic
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)" # prefer $() over backticks
files="$(find /var/log -name '*.gz' | wc -l)"
(( count = files + 1 )) # arithmetic context
echo $(( 7 / 2 )) # 3 (integer division only)
(( count > 100 )) && echo "log buildup"
((i++)); ((total += batch))
echo $(( RANDOM % 6 + 1 )) # dice roll
awk 'BEGIN { printf "%.2f\n", 7/2 }' # need floats? use awk or bc
Everything here compounds with the interactive tricks in the Bash CLI One-Liners Cheatsheet. The loop you prototype at the prompt becomes the script you commit.
Deepen your understanding in Ansible Cheatsheet
Related Cheatsheets
- Bash sed & awk: substitution, address ranges, capture groups, and awk field handling for when plain Bash string manipulation runs out of road
- Bash CLI One-Liners: find/xargs, grep, jq, rsync, and process-triage pipelines worth running interactively before they ever become scripts
- Go (Golang): a different escape hatch. When a script needs real types, tests, and a single static binary, port it to Go
More Bash pages live in the Bash group, and everything else is in the cheatsheet library.
Similar Articles
Related Content
More from development
A cost cheatsheet for running a product cheaply: free-tier hosting, serverless databases, auth, and …
Go cheatsheet covering the go toolchain, syntax essentials, goroutines and channels, table-driven …
You Might Also Like
Quick-reference tmux cheatsheet: sessions, windows, panes, copy mode, synchronize-panes, .tmux.conf …
Quick-reference Ubuntu terminal cheatsheet: apt and dpkg, snap, systemd and journalctl, ufw, users …

