Appendix A: Bash Scripting Cheat Sheet A quick-reference guide for writing and debugging Bash scripts on macOS. This cheat sheet focuses on practical patterns used in enterprise macOS management and security automation.
A.1 Variables name = "Sammy"
echo "Hello, $name "
readonly PI = 3 .14 # constant
unset name # delete variable
A.2 Conditionals if [ " $var " -eq 1 ] ; then
echo "Equal"
elif [ " $var " -gt 1 ] ; then
echo "Greater"
else
echo "Less or unset"
fi
A.2.1 Common Test Operators Test Description -e FILE File exists -f FILE File is a regular file -d DIR Directory exists -z STR String is empty -n STR String is not empty "$a" == "$b" Strings are equal "$a" != "$b" Strings not equal
A.3 Loops for file in *.txt; do
echo " $file "
done
while read line; do
echo " $line "
done < file.txt
until [ " $n " -ge 5 ] ; do
echo " $n "
(( n++))
done
A.4 Functions greet() {
echo "Hello, $1 "
}
greet "macOS"
A.5 Arrays fruits =( "apple" "banana" "cherry" )
echo " ${ fruits [1] } " # banana
echo " ${# fruits [@] } " # count
A.6 String Manipulation str = "macOS"
echo " ${ str ,, } " # lowercase
echo " ${ str ^^ } " # uppercase
echo " ${ str : 1 : 3 } " # substring
echo " ${ str /m/Mac } " # replace
A.7 File Descriptors and Redirection command > out.txt # stdout
command >> out.txt # append
command 2 > err.txt # stderr
command & > all.txt # both stdout + stderr
A.8 Command Substitution today = $( date)
echo "Today is $today "
A.9 Useful Shortcuts Shortcut Meaning Ctrl + A Beginning of line Ctrl + E End of line Ctrl + U Delete to beginning Ctrl + K Delete to end Ctrl + R Reverse search in history !! Repeat last command !n Run command n from history
A.10 Script Template #!/bin/bash
set -euo pipefail
echo "Script started"
# Your logic here
echo "Done"
A.11 File Permission Basics chmod +x script.sh # make executable
chmod 644 file.txt # rw-r--r--
chown user:staff file # change owner
A.12 macOS Specific Tips open -a "TextEdit" file.txt # open file with GUI app
osascript -e 'display dialog "Hello!"' # show dialog
defaults read com.apple.finder # read plist settings
system_profiler SPHardwareDataType # hardware info
A.13 Debugging bash -x script.sh # trace execution
set -x # enable tracing
trap 'echo "Failed at $LINENO"' ERR
A.14 Safe Scripting Practices Use set -euo pipefail for strict error handling Quote variables: "$var" to prevent word splitting Validate inputs before use Avoid parsing ls, use find or stat Check return codes: if ! command; then echo "Failed"; fi Use absolute paths in scripts: /usr/local/bin/tool vs tool A.15 Error Handling Patterns # Exit on error with cleanup
set -e
trap 'cleanup_function' EXIT
# Log errors
log_error() {
echo "[ERROR] $( date) : $* " >& 2
}
# Check command success
if ! command; then
log_error "Command failed"
exit 1
fi
# Retry with backoff
retry() {
local max_attempts = 3
local delay = 2
for (( i = 1 ; i<= max_attempts; i++)) ; do
if command; then
return 0
fi
sleep $delay
delay = $(( delay * 2 ))
done
return 1
}
A.16 Logging and Output # Log to file with timestamp
log_file = "/var/log/script.log"
log() {
echo "[ $( date '+%Y-%m-%d %H:%M:%S' ) ] $* " | tee -a " $log_file "
}
# Quiet mode support
if [[ " ${ QUIET :- false } " != "true" ]] ; then
echo "Verbose output enabled"
fi
# Redirect output conditionally
if [[ -n " ${ LOG_DIR :- } " ]] ; then
exec > >( tee -a " ${ LOG_DIR } /script.log" )
exec 2 >& 1
fi
A.17 Enterprise Script Patterns A.17.1 Check Root Privileges if [[ $EUID -ne 0 ]] ; then
echo "This script must be run as root" >& 2
exit 1
fi
A.17.2 Check macOS Version os_version = $( sw_vers -productVersion | cut -d. -f1,2)
if [[ $( echo " $os_version >= 14.0" | bc -l) -eq 0 ]] ; then
echo "macOS 14.0+ required"
exit 1
fi
A.17.3 MDM Profile Check check_mdm_profile() {
local profile_identifier = " $1 "
if profiles -P | grep -q " $profile_identifier " ; then
return 0
else
return 1
fi
}
A.17.4 Process Check and Kill # Check if process is running
if pgrep -x "ApplicationName" > /dev/null; then
echo "Application is running"
pkill -x "ApplicationName"
fi
A.17.5 JSON Parsing (with jq) # Parse JSON from API
response = $( curl -s "https://api.example.com/data" )
value = $( echo " $response " | jq -r '.key.subkey' )
# Create JSON
json_data = $( jq -n \
--arg key "value" \
'{key: $key}' )
A.17.6 Plist Operations # Read plist value
defaults read /path/to/file.plist Key
# Write plist value
defaults write /path/to/file.plist Key -string "value"
# Delete plist key
defaults delete /path/to/file.plist Key
# Using PlistBuddy
/usr/libexec/PlistBuddy -c "Print :Key" file.plist
/usr/libexec/PlistBuddy -c "Set :Key value" file.plist
A.18 Resources man bash — Bash manual help — Bash built-ins help man -k something — Search man pages brew install bash — Install latest Bash (via Homebrew) See Appendix C for additional tools and resources December 3, 2025 June 8, 2025