Click any command to expand the explanation and examples.
📝 Variables & Strings
name="value" basics
= sign — this is the #1 Bash gotcha.
name="Alice" count=42 path="/usr/local/bin"UseUse with $
echo “Hello $name” echo “There are ${count} items”
${var} when the variable is next to other text: ”${name}_backup”
"double quotes" vs 'single quotes' basics
name="world" echo "Hello $name" # Hello world echo 'Hello $name' # Hello $nameUse double quotes for most things
Use single quotes when you want literal $, `, or </pre>
${#string} — string length strings
msg="Hello"
echo ${#msg} # 5
${string:offset:length} — substring strings
str="Hello World"
echo ${str:0:5} # Hello
echo ${str:6} # World
echo ${str: -3} # rld (note the space before -)
${string/pattern/replacement} — search & replace strings
file="photo.jpg"
echo ${file/.jpg/.png} # photo.png
path=“/home/user/docs”
echo ${path////\} # \home\user\docs (replace all)
Single / = first match, double // = all matches
${var:-default} — default values strings
echo ${NAME:-"Anonymous"} # Anonymous (if NAME is unset)
echo ${PORT:-3000} # 3000 (if PORT is unset)
:= also assigns the default
echo ${NAME:=“Anonymous”} # sets NAME to Anonymous
🔀 Conditionals
if / elif / else flow
[[ ]] for tests (safer than [ ]).
if [[ $age -gt 18 ]]; then echo "Adult" elif [[ $age -eq 18 ]]; then echo "Just turned 18" else echo "Minor" fi
String comparisons test
[[ ]].
[[ $a == $b ]] # equal [[ $a != $b ]] # not equal [[ $a == *.txt ]] # glob pattern match [[ $a =~ ^[0-9]+$ ]] # regex match [[ -z $a ]] # string is empty [[ -n $a ]] # string is not empty
Number comparisons test
[[ ]].
[[ $a -eq $b ]] # equal [[ $a -ne $b ]] # not equal [[ $a -gt $b ]] # greater than [[ $a -ge $b ]] # greater or equal [[ $a -lt $b ]] # less than [[ $a -le $b ]] # less or equalOr use (( )) for arithmetic comparisons
(( a > b )) (( a >= 10 && a <= 20 ))
File tests test
[[ -f file.txt ]] # file exists (regular file) [[ -d mydir ]] # directory exists [[ -e path ]] # anything exists (file, dir, link) [[ -r file ]] # file is readable [[ -w file ]] # file is writable [[ -x file ]] # file is executable [[ -s file ]] # file is not empty [[ -L file ]] # file is a symlinkExample
if [[ -f config.json ]]; then echo “Config found” fi
case statement flow
case $1 in
start)
echo "Starting..."
;;
stop)
echo "Stopping..."
;;
restart)
echo "Restarting..."
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
🔁 Loops
for loop loop
# Over a list for fruit in apple banana cherry; do echo "$fruit" doneOver files
for file in *.txt; do echo “Processing $file” done
C-style
for ((i=0; i<10; i++)); do echo “$i” done
Over a range
for i in {1..5}; do echo “$i” done
while loop loop
# Count to 5 i=1 while [[ $i -le 5 ]]; do echo "$i" ((i++)) doneRead a file line by line
while IFS= read -r line; do echo “$line” done < file.txt
Infinite loop
while true; do echo “Running…” sleep 1 done
Loop over command output loop
# Process each line while IFS= read -r line; do echo "Found: $line" done < <(grep -r "TODO" src/)PreferOr with a for loop (splits on whitespace)
for pid in $(pgrep node); do echo “Node PID: $pid” done
while read over for — it handles spaces in filenames correctly.
⚙️ Functions
function definition function
greet() {
echo "Hello, $1!"
}
greet “Alice” # Hello, Alice!
With multiple args
add() {
echo $(( $1 + $2 ))
}
result=$(add 3 5)
echo “$result” # 8
$1, $2, etc. are positional arguments. $@ is all arguments. $# is the count.
Return values function
echo + command substitution for values.
# Return a value via echo
get_name() {
echo "Alice"
}
name=$(get_name)
Return success/failure via return
is_even() {
(( $1 % 2 == 0 )) && return 0 || return 1
}
if is_even 4; then
echo “Even”
fi
🔧 Script Arguments & Special Variables
$0, $1, $@, $#, $? special
$0 # Script name $1 # First argument $2 # Second argument $@ # All arguments (as separate words) $* # All arguments (as one string) $# # Number of arguments $? # Exit code of last command $$ # PID of current script $! # PID of last background processExample: ./deploy.sh production —force
$0 = ./deploy.sh
$1 = production
$2 = —force
$# = 2
set -euo pipefail safety
#!/bin/bash set -euo pipefail-e Exit on any error
-u Error on undefined variables
-o pipefail Catch errors in piped commands
Without this, scripts silently continue after errors — which leads to disasters.
🚀 Common One-Liners
Find and replace in files one-liner
# macOS (BSD sed)
find . -name "*.js" -exec sed -i '' 's/old/new/g' {} +
Linux (GNU sed)
find . -name “*.js” -exec sed -i ‘s/old/new/g’ {} +
Preview first (no changes)
grep -rn “old” —include=“*.js”
Find large files one-liner
# Files larger than 100MB find . -type f -size +100MWith human-readable sizes (Linux)
find . -type f -size +100M -exec ls -lh {} +
Top 10 largest files
du -ah . | sort -rh | head -10
Watch a command one-liner
# Every 2 seconds watch -n 2 'docker ps'macOS (no watch by default)
while true; do clear; docker ps; sleep 2; done
Process CSV / columnar data one-liner
# Get second column (space-separated)
awk '{print $2}' file.txt
Get first column (comma-separated)
awk -F’,’ ‘{print $1}’ data.csv
Sum a column
awk ‘{sum += $1} END {print sum}’ numbers.txt
Unique sorted lines
sort file.txt | uniq
Count occurrences
sort file.txt | uniq -c | sort -rn
Parallel execution with xargs one-liner
# Convert images in parallel (4 at a time)
find . -name "*.png" | xargs -P 4 -I {} convert {} -resize 50% {}
Delete files matching a pattern
find . -name “*.log” -print0 | xargs -0 rm
Run a command for each line of input
cat urls.txt | xargs -I {} curl -s {}