1#!/usr/bin/env bash
2set -euo pipefail
3
4# Cleanup and Signal Handling Patterns
5# Demonstrates proper cleanup of resources and graceful shutdown
6
7# ============================================================================
8# Color definitions for output
9# ============================================================================
10
11readonly RED='\033[0;31m'
12readonly GREEN='\033[0;32m'
13readonly YELLOW='\033[1;33m'
14readonly BLUE='\033[0;34m'
15readonly CYAN='\033[0;36m'
16readonly NC='\033[0m' # No Color
17
18# ============================================================================
19# Global Variables for Cleanup Tracking
20# ============================================================================
21
22# Track temporary files and directories
23declare -a TEMP_FILES=()
24declare -a TEMP_DIRS=()
25
26# Lock file location
27LOCK_FILE=""
28
29# Background process PID
30BG_PROCESS_PID=""
31
32# ============================================================================
33# Cleanup Functions
34# ============================================================================
35
36# Cleanup function called on script exit
37cleanup_on_exit() {
38 local exit_code=$?
39
40 echo
41 echo -e "${CYAN}=== Cleanup Handler (EXIT) ===${NC}"
42 echo "Exit code: $exit_code"
43
44 # Clean up temporary files
45 if [[ ${#TEMP_FILES[@]} -gt 0 ]]; then
46 echo "Removing temporary files..."
47 for file in "${TEMP_FILES[@]}"; do
48 if [[ -f "$file" ]]; then
49 rm -f "$file"
50 echo -e " ${GREEN}✓${NC} Removed: $file"
51 fi
52 done
53 fi
54
55 # Clean up temporary directories
56 if [[ ${#TEMP_DIRS[@]} -gt 0 ]]; then
57 echo "Removing temporary directories..."
58 for dir in "${TEMP_DIRS[@]}"; do
59 if [[ -d "$dir" ]]; then
60 rm -rf "$dir"
61 echo -e " ${GREEN}✓${NC} Removed: $dir"
62 fi
63 done
64 fi
65
66 # Remove lock file
67 if [[ -n "$LOCK_FILE" && -f "$LOCK_FILE" ]]; then
68 rm -f "$LOCK_FILE"
69 echo -e " ${GREEN}✓${NC} Released lock: $LOCK_FILE"
70 fi
71
72 # Kill background processes
73 if [[ -n "$BG_PROCESS_PID" ]] && kill -0 "$BG_PROCESS_PID" 2>/dev/null; then
74 echo "Terminating background process (PID $BG_PROCESS_PID)..."
75 kill "$BG_PROCESS_PID" 2>/dev/null || true
76 wait "$BG_PROCESS_PID" 2>/dev/null || true
77 echo -e " ${GREEN}✓${NC} Background process terminated"
78 fi
79
80 echo -e "${GREEN}Cleanup complete${NC}"
81}
82
83# Handle interrupt signal (Ctrl+C)
84cleanup_on_interrupt() {
85 echo
86 echo -e "${YELLOW}=== Cleanup Handler (SIGINT) ===${NC}"
87 echo "Caught interrupt signal (Ctrl+C)"
88 echo "Performing graceful shutdown..."
89
90 # Exit will trigger cleanup_on_exit
91 exit 130
92}
93
94# Handle termination signal
95cleanup_on_terminate() {
96 echo
97 echo -e "${YELLOW}=== Cleanup Handler (SIGTERM) ===${NC}"
98 echo "Caught termination signal"
99 echo "Performing graceful shutdown..."
100
101 exit 143
102}
103
104# Handle hangup signal
105cleanup_on_hangup() {
106 echo
107 echo -e "${YELLOW}=== Cleanup Handler (SIGHUP) ===${NC}"
108 echo "Caught hangup signal"
109 echo "Performing graceful shutdown..."
110
111 exit 129
112}
113
114# ============================================================================
115# Setup Signal Handlers
116# ============================================================================
117
118setup_traps() {
119 echo -e "${CYAN}Setting up signal handlers...${NC}"
120
121 # EXIT: Always called when script exits (success or failure)
122 trap cleanup_on_exit EXIT
123
124 # SIGINT: Interrupt from keyboard (Ctrl+C)
125 trap cleanup_on_interrupt INT
126
127 # SIGTERM: Termination signal
128 trap cleanup_on_terminate TERM
129
130 # SIGHUP: Hangup detected on controlling terminal
131 trap cleanup_on_hangup HUP
132
133 echo -e "${GREEN}✓${NC} Signal handlers installed: EXIT, INT, TERM, HUP"
134 echo
135}
136
137# ============================================================================
138# Resource Management Functions
139# ============================================================================
140
141# Create a temporary file and register it for cleanup
142create_temp_file() {
143 local prefix="${1:-temp}"
144 local temp_file
145
146 temp_file=$(mktemp "/tmp/${prefix}.XXXXXX")
147 TEMP_FILES+=("$temp_file")
148
149 echo -e "${GREEN}✓${NC} Created temp file: $temp_file"
150 echo "$temp_file"
151}
152
153# Create a temporary directory and register it for cleanup
154create_temp_dir() {
155 local prefix="${1:-tempdir}"
156 local temp_dir
157
158 temp_dir=$(mktemp -d "/tmp/${prefix}.XXXXXX")
159 TEMP_DIRS+=("$temp_dir")
160
161 echo -e "${GREEN}✓${NC} Created temp directory: $temp_dir"
162 echo "$temp_dir"
163}
164
165# Acquire a lock file
166acquire_lock() {
167 local lock_name="${1:-script}"
168 LOCK_FILE="/tmp/${lock_name}.lock"
169
170 if [[ -f "$LOCK_FILE" ]]; then
171 local lock_pid
172 lock_pid=$(cat "$LOCK_FILE")
173
174 if kill -0 "$lock_pid" 2>/dev/null; then
175 echo -e "${RED}✗${NC} Lock already held by process $lock_pid"
176 return 1
177 else
178 echo -e "${YELLOW}⚠${NC} Stale lock file found, removing..."
179 rm -f "$LOCK_FILE"
180 fi
181 fi
182
183 echo $$ > "$LOCK_FILE"
184 echo -e "${GREEN}✓${NC} Lock acquired: $LOCK_FILE"
185 return 0
186}
187
188# Start a background process that will be cleaned up
189start_background_process() {
190 echo "Starting background process..."
191
192 (
193 echo "Background process started (PID $$)"
194 for i in {1..30}; do
195 echo " [BG] Working... ($i/30)"
196 sleep 1
197 done
198 echo "Background process completed"
199 ) &
200
201 BG_PROCESS_PID=$!
202 echo -e "${GREEN}✓${NC} Background process started (PID $BG_PROCESS_PID)"
203}
204
205# ============================================================================
206# Demo Functions
207# ============================================================================
208
209demo_temp_file_cleanup() {
210 echo -e "${BLUE}=== Temporary File Management Demo ===${NC}\n"
211
212 # Create several temp files
213 local file1 file2 file3
214 file1=$(create_temp_file "demo1")
215 file2=$(create_temp_file "demo2")
216 file3=$(create_temp_file "demo3")
217
218 # Write some data
219 echo "Data in file 1" > "$file1"
220 echo "Data in file 2" > "$file2"
221 echo "Data in file 3" > "$file3"
222
223 echo
224 echo "Temporary files created and will be cleaned up on exit"
225 echo "Total temp files: ${#TEMP_FILES[@]}"
226 echo
227}
228
229demo_temp_dir_cleanup() {
230 echo -e "${BLUE}=== Temporary Directory Management Demo ===${NC}\n"
231
232 # Create temp directory
233 local temp_dir
234 temp_dir=$(create_temp_dir "workspace")
235
236 # Create some files in it
237 touch "$temp_dir/file1.txt"
238 touch "$temp_dir/file2.txt"
239 mkdir -p "$temp_dir/subdir"
240 touch "$temp_dir/subdir/file3.txt"
241
242 echo "Created directory structure:"
243 ls -R "$temp_dir" | sed 's/^/ /'
244 echo
245}
246
247demo_lock_file() {
248 echo -e "${BLUE}=== Lock File Demo ===${NC}\n"
249
250 if acquire_lock "cleanup_demo"; then
251 echo "Performing work while holding lock..."
252 sleep 1
253 echo -e "${GREEN}✓${NC} Work completed"
254 else
255 echo -e "${RED}✗${NC} Could not acquire lock"
256 return 1
257 fi
258 echo
259}
260
261demo_background_process_cleanup() {
262 echo -e "${BLUE}=== Background Process Cleanup Demo ===${NC}\n"
263
264 start_background_process
265
266 echo
267 echo "Background process running..."
268 echo "Script will clean it up on exit"
269 sleep 2
270 echo
271}
272
273demo_graceful_shutdown() {
274 echo -e "${BLUE}=== Graceful Shutdown Demo ===${NC}\n"
275
276 echo "This demo shows cleanup on interrupt"
277 echo -e "${YELLOW}Press Ctrl+C to trigger graceful shutdown${NC}"
278 echo "Or wait 5 seconds for normal exit..."
279 echo
280
281 # Simulate long-running work
282 for i in {1..5}; do
283 echo "Working... ($i/5)"
284 sleep 1
285 done
286
287 echo -e "${GREEN}✓${NC} Work completed normally"
288 echo
289}
290
291# ============================================================================
292# Main Execution
293# ============================================================================
294
295main() {
296 echo -e "${BLUE}╔════════════════════════════════════════════╗${NC}"
297 echo -e "${BLUE}║ Cleanup & Signal Handling Demo ║${NC}"
298 echo -e "${BLUE}╚════════════════════════════════════════════╝${NC}"
299 echo
300
301 # Setup cleanup handlers
302 setup_traps
303
304 # Run demos
305 demo_temp_file_cleanup
306 demo_temp_dir_cleanup
307 demo_lock_file
308 demo_background_process_cleanup
309 demo_graceful_shutdown
310
311 echo -e "${GREEN}=== Demo Complete ===${NC}"
312 echo "Cleanup will run automatically on exit..."
313 echo
314
315 # EXIT trap will handle cleanup
316}
317
318main "$@"