⏳
Loading cheatsheet...
Variables, conditionals, loops, functions, text processing, arrays, debugging, and advanced scripting patterns.
#!/usr/bin/env bash
set -euo pipefail # Exit on error, undefined vars, pipe failures
# ── Variables ──
NAME="John"
AGE=30
IS_ADMIN=true
PI=3.14159
EMPTY=""
# Variable interpolation
echo "Hello, $NAME"
echo "Hello, ${NAME}" # Braces for clarity
echo "Age: $((AGE + 5))" # Arithmetic expansion
# Command substitution
CURRENT_DIR=$(pwd)
FILE_COUNT=$(ls -1 | wc -l)
TODAY=$(date +%Y-%m-%d)
IP_ADDR=$(hostname -I | awk '{print $1}')
# ── Strings ──
GREETING="Hello, World!"
echo ${'#GREETING'} # Length: 13
echo ${'GREETING:0:5'} # Substring: "Hello"
echo ${'GREETING:7'} # From index 7: "World!"
echo ${'GREETING#"World!"'} # Remove suffix: "Hello, "
echo ${'GREETING#"o"'} # Remove shortest suffix
echo ${'GREETING##"W"'} # Remove longest suffix
echo ${'GREETING#*"o"'} # Remove shortest prefix
echo ${'GREETING##*"o"'} # Remove longest prefix
echo ${'GREETING^^'} # Uppercase all
echo ${'GREETING,,'} # Lowercase all
# String replacement
TEXT="hello world"
echo ${'TEXT/world/World'} # "hello World"
echo ${'TEXT//l/L'} # "heLLo WorLd" (all)
# Default values
echo ${'UNDEFINED:-"default"'} # Use default if unset/null
echo ${'UNDEFINED:="default"'} # Assign default if unset/null
echo ${'NAME:+"exists"'} # Use "exists" if NAME is set
# ── Special Variables ──
echo $$ # Current PID
echo $0 # Script name
echo $1-$9 # Positional parameters
echo $# # Number of parameters
echo $@ # All parameters as separate words
echo $* # All parameters as single string
echo $? # Exit status of last command
echo $! # PID of last background process| Quote | Expansion | Use For |
|---|---|---|
| "double" | Variables, command sub, escapes | Strings with variables |
| 'single' | No expansion at all | Literal strings |
| \backslash | Escape one character | Special chars |
| Operation | Syntax |
|---|---|
| Declare | FRUITS=("apple" "banana" "cherry") |
| Access | ${FRUITS[0]} → apple |
| All items | ${FRUITS[@]} |
| Length | ${#FRUITS[@]} |
| Append | FRUITS+=("date") |
| Iterate | for f in "${FRUITS[@]}"; do echo $f; done |
| Slice | ${FRUITS[@]:1:2} → banana cherry |
#!/usr/bin/env bash
# ── If / Elif / Else ──
AGE=25
if [ "$AGE" -ge 18 ]; then
echo "Adult"
elif [ "$AGE" -ge 13 ]; then
echo "Teenager"
else
echo "Child"
fi
# ── Test Operators ──
FILE="/etc/passwd"
# File tests
[ -f "$FILE" ] && echo "Regular file exists"
[ -d "$FILE" ] && echo "Directory exists"
[ -r "$FILE" ] && echo "Readable"
[ -w "$FILE" ] && echo "Writable"
[ -x "$FILE" ] && echo "Executable"
[ -s "$FILE" ] && echo "Non-empty file"
[ -e "$FILE" ] && echo "Exists"
# String tests
[ "$NAME" = "John" ] && echo "Equals"
[ "$NAME" != "Jane" ] && echo "Not equal"
[ -z "$EMPTY" ] && echo "Empty string"
[ -n "$NAME" ] && echo "Non-empty string"
# Numeric tests
[ 10 -eq 10 ] && echo "Equal"
[ 10 -ne 5 ] && echo "Not equal"
[ 10 -gt 5 ] && echo "Greater than"
[ 10 -ge 10 ] && echo "Greater or equal"
[ 5 -lt 10 ] && echo "Less than"
[ 5 -le 5 ] && echo "Less or equal"
# ── Case Statement ──
read -p "Choose (start|stop|restart): " ACTION
case "$ACTION" in
start)
echo "Starting service..."
;;
stop)
echo "Stopping service..."
;;
restart|reload)
echo "Restarting service..."
;;
*)
echo "Unknown action: $ACTION"
exit 1
;;
esac
# ── For Loops ──
for i in 1 2 3 4 5; do
echo "Number: $i"
done
for file in *.sh; do
echo "Processing: $file"
done
for ((i=0; i<10; i++)); do
echo "Count: $i"
done
# ── While Loop ──
COUNT=0
while [ $COUNT -lt 5 ]; do
echo "Count: $COUNT"
COUNT=$((COUNT + 1))
done
# ── Until Loop ──
until [ -f "/tmp/ready" ]; do
echo "Waiting..."
sleep 1
done| Syntax | Use Case |
|---|---|
| [[ -f file ]] | Modern test (preferred) |
| [ -f file ] | POSIX test |
| (( a > b )) | Arithmetic comparison |
| (( a == b )) | Arithmetic equality |
| Command | Purpose |
|---|---|
| break | Exit loop immediately |
| continue | Skip to next iteration |
| sleep N | Pause for N seconds |
#!/usr/bin/env bash
# ── Function Definition ──
greet() {
local name="${'1:-World'}"
local count="${'2:-1'}"
echo "Hello, $name! (called $count times)"
}
greet "John" # Hello, John!
greet # Hello, World!
greet "Alice" 3 # Hello, Alice! (called 3 times)
# ── Function with return value ──
is_file_exists() {
local file="$1"
[ -f "$file" ] && return 0 || return 1
}
is_file_exists "/etc/passwd" && echo "Found" || echo "Not found"
# ── Function that captures output ──
get_file_info() {
local file="$1"
if [ ! -f "$file" ]; then
echo "Error: File not found: $file" >&2
return 1
fi
local size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file")
local lines=$(wc -l < "$file")
echo "Size: $size bytes, Lines: $lines"
}
INFO=$(get_file_info "script.sh")
echo "$INFO"
# ── Arguments Processing ──
usage() {
echo "Usage: $0 [-v] [-f FILE] [-n COUNT] NAME"
echo " -v Verbose mode"
echo " -f FILE Input file"
echo " -n COUNT Number of iterations"
echo " -h Show this help"
exit 1
}
VERBOSE=false
FILE=""
COUNT=10
while getopts "vf:n:h" opt; do
case $opt in
v) VERBOSE=true ;;
f) FILE="$OPTARG" ;;
n) COUNT="$OPTARG" ;;
h|*) usage ;;
esac
done
shift $((OPTIND - 1))
NAME="${'1:-default'}"
# ── Error Handling ──
set -euo pipefail
trap 'echo "Error on line $LINENO"' ERR
trap 'echo "Cleaning up..."; rm -f /tmp/mystatus.$$; exit' EXITset -euo pipefail at the top of scripts for safety. Use local for function variables to avoid polluting global scope. Use trap for cleanup on exit or error handling.#!/usr/bin/env bash
# ── awk ──
# Print specific columns
awk '{print $1, $3}' file.txt
# Filter rows
awk '$3 > 100' file.txt
# Custom delimiter
awk -F',' '{print $1, $2}' csv.txt
# Conditional formatting
awk '{printf "%-15s %10d\n", $1, $3}' file.txt
# ── sed ──
# Replace text
sed 's/old/new/g' file.txt # Global replace
sed 's/old/new/gi' file.txt # Case-insensitive
sed -i 's/old/new/g' file.txt # In-place edit
sed '2d' file.txt # Delete line 2
sed '1,5d' file.txt # Delete lines 1-5
sed -n '/pattern/p' file.txt # Print matching lines
sed -i 's/^#//' file.txt # Uncomment lines
# ── grep ──
grep "pattern" file.txt # Basic search
grep -i "pattern" file.txt # Case-insensitive
grep -r "pattern" /dir/ # Recursive
grep -n "pattern" file.txt # With line numbers
grep -v "pattern" file.txt # Invert match
grep -c "pattern" file.txt # Count matches
grep -E "pat1|pat2" file.txt # Extended regex (OR)
grep -A 5 -B 2 "error" log.txt # Context lines
grep -l "pattern" *.sh # Files matching
# ── cut ──
cut -d',' -f1,3 file.csv # Fields 1 and 3
cut -d' ' -f1 file.txt # First field
cut -c1-10 file.txt # Characters 1-10
# ── sort & uniq ──
sort file.txt # Sort alphabetically
sort -n file.txt # Sort numerically
sort -r file.txt # Reverse sort
sort -k2 -n file.txt # Sort by field 2
sort file.txt | uniq -c # Count duplicates
sort file.txt | uniq -u # Remove duplicates| Operator | Description |
|---|---|
| > file | Redirect stdout (overwrite) |
| >> file | Redirect stdout (append) |
| 2> file | Redirect stderr |
| &> file | Redirect stdout + stderr |
| < file | Read from file as stdin |
| << EOF | Here document (multi-line input) |
| <<< str | Here string |
| | | Pipe stdout to next command |
| Command | Purpose |
|---|---|
| wc -l file | Count lines |
| head -n 20 file | First 20 lines |
| tail -f file | Follow file (live) |
| tee file | Output to stdout and file |
| xargs command | Build args from stdin |
| find . -name "*.sh" | Find .sh files |
| diff file1 file2 | Compare files |
[ is POSIX test (portable across shells). It is a built-in command.[[ is a Bash keyword (more powerful, non-portable). It supports pattern matching (=~), logical operators (&&, || without quoting issues), and does not require quoting variables. Prefer [[ for Bash scripts; use [ for POSIX-compatible scripts.
set -e exits immediately if any command exits with non-zero status.set -u treats unset variables as errors. set -o pipefail makes a pipeline return the exit status of the last command that failed (not the last command in the pipe). Together, these prevent silent failures in scripts.