$ cheat sheet
Bash
Scripting
Everything you reach for. Copy, paste, ship.
#!
Shebang & basics
2 snippetsminimal shebang
#!/usr/bin/env bash set -euo pipefail # exit on error, unset var, pipe fail
Always the first line. Tells the OS which interpreter to use.
run & debug
chmod +x script.sh bash -x script.sh # trace mode, prints each line before running
Make executable and trace every command.
$
Variables
3 snippetsdeclare & use
name="Mayuresh"
age=28
echo "Hello, $name"
echo "Age: ${age}" # braces = safe practiceNo spaces around = when assigning.
readonly & unset
readonly API_KEY="abc123" unset age
default values
echo ${NAME:-"guest"} # fallback if unset
echo ${COUNT:=0} # fallback + assign
echo ${MUST:?"required"} # error if unsetUse :- to fallback, := to also assign, :? to error if unset.
${}
Parameter expansion
5 snippetssubstring & length
str="hello world"
echo ${#str} # length → 11
echo ${str:6} # from index 6 → world
echo ${str:0:5} # first 5 chars → hello
echo ${str: -5} # last 5 chars → worldfind & replace
str="foo foo foo"
echo ${str/foo/bar} # first match → bar foo foo
echo ${str//foo/bar} # all matches → bar bar bar
echo ${str/#foo/bar} # only at start
echo ${str/%foo/bar} # only at endstrip prefix / suffix
path="/usr/local/bin/script.sh"
echo ${path##*/} # strip longest prefix → script.sh
echo ${path%/*} # strip shortest suffix → /usr/local/bin
echo ${path%%.*} # strip from first dot
echo ${path#*/} # strip shortest prefix → usr/local/bin/script.shSingle # or % = shortest match. Double = longest (greedy).
case conversion
str="Hello World"
echo ${str,,} # all lowercase → hello world
echo ${str^^} # all uppercase → HELLO WORLD
echo ${str,} # first char lowercase
echo ${str^} # first char uppercaseindirect expansion
var="PATH"
echo ${!var} # expands to value of $PATH
# list all vars matching a prefix
echo ${!AWS_*} # → AWS_ACCESS_KEY_ID AWS_SECRET ...Use !varname to expand the value of the variable named by varname.
""
Strings & quotes
3 snippetssingle vs double
echo 'Hello $USER' # → Hello $USER echo "Hello $USER" # → Hello mayuresh
Single quotes = literal. Double quotes = expand variables and escapes.
heredoc
cat << EOF line one line two EOF # indented heredoc (bash 4+) cat <<- EOF indented content EOF
Great for multiline strings or passing text to commands.
string test patterns
[[ "$str" == *.log ]] # glob match [[ "$str" =~ ^[0-9]+$ ]] # regex match [[ -z "$str" ]] # empty string [[ -n "$str" ]] # non-empty string
[]
Arrays
3 snippetsbasics
fruits=("apple" "banana" "cherry")
echo ${fruits[0]} # apple
echo ${fruits[@]} # all elements
echo ${#fruits[@]} # length → 3
echo ${!fruits[@]} # all indices → 0 1 2add, remove, slice
fruits+=("mango") # append
unset fruits[1] # remove banana
echo ${fruits[@]:1:2} # slice: 2 items from index 1iterate with index
for i in "${!fruits[@]}"; do
echo "$i: ${fruits[$i]}"
done{}
Dictionaries
4 snippetsdeclare & set
declare -A config config["env"]="prod" config["region"]="us-east-1" config["replicas"]="3"
Requires bash 4+. Use declare -A before assigning.
read & check keys
echo ${config["env"]} # prod
echo ${config[@]} # all values
echo ${!config[@]} # all keys
echo ${#config[@]} # count → 3
# check if key exists
[[ -v config["env"] ]] && echo "exists"iterate keys & values
for key in "${!config[@]}"; do
echo "$key = ${config[$key]}"
doneinline declaration
declare -A ports=( ["http"]="80" ["https"]="443" ["ssh"]="22" ) unset ports["http"] # delete a key
Declare and populate in one shot.
if
Conditionals
3 snippetsif / elif / else
if [[ $score -ge 90 ]]; then echo "A" elif [[ $score -ge 75 ]]; then echo "B" else echo "C" fi
file & number checks
[[ -f file ]] && [[ -s file ]] # exists and non-empty [[ -d /tmp ]] # is directory [[ -x script.sh ]] # is executable [[ $a -lt $b ]] # less than [[ $a -eq $b ]] # equal
case statement
case "$env" in
prod)
replicas=3 ;;
staging)
replicas=1 ;;
*)
echo "unknown env" && exit 1 ;;
esacCleaner than long if/elif chains for matching strings.
for
Loops
3 snippetsfor range & array
for i in {1..5}; do echo $i; done
for f in "${files[@]}"; do
echo "$f"
donewhile & until
count=0 while [[ $count -lt 5 ]]; do (( count++ )) done until [[ -f /tmp/ready ]]; do sleep 1 done
read lines from file
while IFS= read -r line; do echo "$line" done < file.txt
IFS= preserves whitespace. -r prevents backslash interpretation.
fn()
Functions
3 snippetsdefine & call
greet() {
local name=$1
echo "Hey, $name"
}
greet "Mayuresh"return a value
add() { echo $(( $1 + $2 )); }
result=$(add 3 4) # → 7Bash functions return exit codes only. Use echo to pass back data.
local variables
process() {
local input=$1
local result
result=$(echo "$input" | tr '[:lower:]' '[:upper:]')
echo "$result"
}Always use local inside functions to avoid polluting global scope.
-f
Options (getopts)
3 snippetsbasic getopts
while getopts ":e:r:v" opt; do
case $opt in
e) ENV=$OPTARG ;;
r) REGION=$OPTARG ;;
v) VERBOSE=1 ;;
?) echo "unknown flag: -$OPTARG" && exit 1 ;;
esac
done
shift $(( OPTIND - 1 )) # remove parsed flagsThe standard way to parse short flags in bash scripts.
usage pattern
usage() {
echo "Usage: $0 -e <env> -r <region> [-v]"
exit 1
}
[[ $# -eq 0 ]] && usagePut this at the top. Clean help text is non-negotiable.
long options (manual)
while [[ $# -gt 0 ]]; do
case $1 in
--env) ENV=$2; shift 2 ;;
--region) REGION=$2; shift 2 ;;
--verbose) VERBOSE=1; shift ;;
*) echo "unknown: $1"; exit 1 ;;
esac
donegetopts doesn't support --long-flags natively. Parse them manually.
I/O
Input / Output
3 snippetsread user input
read -p "Enter name: " name read -sp "Password: " pass # silent read -t 5 -p "Quick: " ans # 5s timeout read -a arr # read into array
redirects
cmd > out.txt # stdout to file (overwrite) cmd >> out.txt # append cmd 2> err.txt # stderr only cmd &> all.txt # stdout + stderr cmd 2>&1 | less # pipe both streams cmd < in.txt # stdin from file
process substitution
diff <(sort file1) <(sort file2) while IFS= read -r line; do echo $line done < <(grep "ERROR" app.log)
Treats command output as a file descriptor. No subshell for while-read.
err
Error handling
3 snippetsstrict mode
set -euo pipefail IFS=$'\n\t' # safer word splitting
Put this at the top of every production script.
trap for cleanup
cleanup() {
echo "cleaning up..."
rm -f /tmp/myfile
}
trap cleanup EXIT
trap 'echo "error on line $LINENO"' ERREXIT fires on any exit, clean, error, or signal.
guard: require tool
require() {
command -v "$1" &>/dev/null || {
echo "$1 not found" >&2; exit 1
}
}
require kubectl
require terraform!!
History & recall
4 snippetsquick recall
!! # re-run last command !$ # last argument of previous command !* # all arguments of previous command !kubectl # re-run last command starting with kubectl !-2 # run the command 2 before last
These work interactively in your terminal session.
history search
history # list all history history 20 # last 20 commands history | grep docker # search history # Ctrl+R # interactive reverse search
history control
export HISTSIZE=10000 export HISTFILESIZE=20000 export HISTCONTROL=ignoredups:erasedups export HISTTIMEFORMAT="%F %T " # timestamp in history
Add to ~/.bashrc to tune history behavior.
fc, fix command
fc # edit last command in $EDITOR fc -l # list recent history fc 42 # edit and re-run history entry 42
Opens last command in your editor so you can fix and re-run.
...
Miscellaneous
6 snippetsarithmetic
echo $(( 10 + 5 * 2 )) # 20 echo $(( 10 % 3 )) # 1 (modulo) (( x++ )) (( x += 5 )) result=$(bc <<< "scale=2; 10/3") # float → 3.33
subshell vs source
( cd /tmp && ls ) # subshell, cwd unchanged after source ~/.bashrc # same shell, env changes stick . ./helpers.sh # same as source, POSIX compatible
. file.sh and source file.sh are identical, both run in current shell.
special variables
echo $0 # script name echo $1 # first arg echo $@ # all args (quoted individually) echo $* # all args (one string) echo $# # arg count echo $? # exit code of last command echo $$ # PID of current shell
brace expansion
echo {a,b,c}.txt # a.txt b.txt c.txt
mkdir -p app/{src,test,docs}
cp file.txt{,.bak} # copy to file.txt.bak
echo {1..5} # 1 2 3 4 5
echo {01..05} # 01 02 03 04 05tee & xargs
echo "hello" | tee output.txt cmd 2>&1 | tee -a debug.log cat pods.txt | xargs kubectl delete pod find . -name "*.log" | xargs rm -f
tee writes to a file and stdout simultaneously. xargs builds command lines from stdin.
sleep, date, printf
sleep 2 # wait 2 seconds date +"%Y-%m-%d %H:%M:%S" # formatted date today=$(date +%Y%m%d) printf "%-15s %5d\n" "pods" 42 # formatted output