1#!/usr/bin/env bash
2set -euo pipefail
3
4# Getopts Demonstration
5# Shows POSIX-compliant argument parsing with getopts
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# Default Values
20# ============================================================================
21
22VERBOSE=false
23OUTPUT_FILE=""
24COUNT=1
25SHOW_HELP=false
26
27# ============================================================================
28# Usage Function
29# ============================================================================
30
31usage() {
32 cat << EOF
33${BLUE}USAGE:${NC}
34 $(basename "$0") [OPTIONS] [ARGUMENTS...]
35
36${BLUE}DESCRIPTION:${NC}
37 Demonstrates POSIX getopts argument parsing.
38 Processes options and remaining positional arguments.
39
40${BLUE}OPTIONS:${NC}
41 -v Enable verbose output
42 -o FILE Specify output file
43 -n COUNT Set count value (default: 1)
44 -h Show this help message
45
46${BLUE}EXAMPLES:${NC}
47 $(basename "$0") -v file1 file2
48 $(basename "$0") -o output.txt -n 5 input.txt
49 $(basename "$0") -vn 3 -o result.log data/*
50
51${BLUE}EXIT CODES:${NC}
52 0 Success
53 1 Invalid option or missing argument
54 2 Invalid argument value
55
56EOF
57}
58
59# ============================================================================
60# Argument Parsing
61# ============================================================================
62
63parse_arguments() {
64 local OPTIND OPTARG opt
65
66 # getopts format: "vho:n:"
67 # - Letters without colon: flag options (no argument)
68 # - Letters with colon: options that require an argument
69 while getopts "vho:n:" opt; do
70 case "$opt" in
71 v)
72 VERBOSE=true
73 ;;
74 h)
75 SHOW_HELP=true
76 ;;
77 o)
78 OUTPUT_FILE="$OPTARG"
79 ;;
80 n)
81 if [[ ! "$OPTARG" =~ ^[0-9]+$ ]]; then
82 echo -e "${RED}Error:${NC} -n requires a numeric argument" >&2
83 usage
84 exit 2
85 fi
86 COUNT="$OPTARG"
87 ;;
88 \?)
89 echo -e "${RED}Error:${NC} Invalid option: -$OPTARG" >&2
90 usage
91 exit 1
92 ;;
93 :)
94 echo -e "${RED}Error:${NC} Option -$OPTARG requires an argument" >&2
95 usage
96 exit 1
97 ;;
98 esac
99 done
100
101 # Shift processed options
102 shift $((OPTIND - 1))
103
104 # Remaining arguments are positional
105 POSITIONAL_ARGS=("$@")
106}
107
108# ============================================================================
109# Display Configuration
110# ============================================================================
111
112display_config() {
113 echo -e "${CYAN}=== Configuration ===${NC}"
114 echo
115
116 echo "Options parsed:"
117 echo " Verbose: $VERBOSE"
118 echo " Output file: ${OUTPUT_FILE:-<not specified>}"
119 echo " Count: $COUNT"
120 echo
121
122 if [[ ${#POSITIONAL_ARGS[@]} -gt 0 ]]; then
123 echo "Positional arguments (${#POSITIONAL_ARGS[@]}):"
124 for i in "${!POSITIONAL_ARGS[@]}"; do
125 echo " [$((i+1))] ${POSITIONAL_ARGS[$i]}"
126 done
127 else
128 echo "No positional arguments provided"
129 fi
130
131 echo
132}
133
134# ============================================================================
135# Processing Function
136# ============================================================================
137
138process_data() {
139 echo -e "${CYAN}=== Processing ===${NC}"
140 echo
141
142 # Verbose logging
143 verbose_log() {
144 if [[ "$VERBOSE" == true ]]; then
145 echo -e "${YELLOW}[VERBOSE]${NC} $*"
146 fi
147 }
148
149 verbose_log "Starting processing with count=$COUNT"
150
151 # Process each positional argument
152 if [[ ${#POSITIONAL_ARGS[@]} -gt 0 ]]; then
153 for arg in "${POSITIONAL_ARGS[@]}"; do
154 verbose_log "Processing: $arg"
155
156 for ((i=1; i<=COUNT; i++)); do
157 echo " Processing '$arg' (iteration $i/$COUNT)"
158
159 if [[ "$VERBOSE" == true ]]; then
160 sleep 0.1 # Small delay in verbose mode to show progress
161 fi
162 done
163 done
164 else
165 echo " No input files to process"
166 fi
167
168 echo
169
170 # Handle output file
171 if [[ -n "$OUTPUT_FILE" ]]; then
172 verbose_log "Writing results to: $OUTPUT_FILE"
173
174 {
175 echo "# Processing Results"
176 echo "# Generated: $(date)"
177 echo "# Count: $COUNT"
178 echo
179 echo "Processed items:"
180 for arg in "${POSITIONAL_ARGS[@]}"; do
181 echo " - $arg"
182 done
183 } > "$OUTPUT_FILE"
184
185 echo -e "${GREEN}✓${NC} Results written to: $OUTPUT_FILE"
186 else
187 verbose_log "No output file specified, results not saved"
188 fi
189
190 echo
191}
192
193# ============================================================================
194# Demo Examples
195# ============================================================================
196
197run_demo_examples() {
198 echo -e "${BLUE}╔════════════════════════════════════════════╗${NC}"
199 echo -e "${BLUE}║ Getopts Demo Examples ║${NC}"
200 echo -e "${BLUE}╚════════════════════════════════════════════╝${NC}"
201 echo
202
203 local script_name
204 script_name=$(basename "$0")
205
206 echo "This script demonstrates getopts argument parsing."
207 echo
208 echo -e "${CYAN}Try these examples:${NC}"
209 echo
210 echo "1. Basic usage with verbose flag:"
211 echo " ./$script_name -v file1.txt file2.txt"
212 echo
213 echo "2. Specify output file and count:"
214 echo " ./$script_name -o output.log -n 3 input.txt"
215 echo
216 echo "3. Combined short options:"
217 echo " ./$script_name -vn 5 -o result.txt data/*"
218 echo
219 echo "4. Show help:"
220 echo " ./$script_name -h"
221 echo
222 echo "5. Test error handling (invalid option):"
223 echo " ./$script_name -x"
224 echo
225 echo "6. Test error handling (missing argument):"
226 echo " ./$script_name -o"
227 echo
228 echo "7. Test error handling (invalid count):"
229 echo " ./$script_name -n abc"
230 echo
231
232 echo -e "${YELLOW}Note:${NC} Running demo with default behavior..."
233 echo
234}
235
236# ============================================================================
237# Main Execution
238# ============================================================================
239
240main() {
241 # Parse command-line arguments
242 declare -a POSITIONAL_ARGS=()
243 parse_arguments "$@"
244
245 # Show help if requested
246 if [[ "$SHOW_HELP" == true ]]; then
247 usage
248 exit 0
249 fi
250
251 # If no arguments provided, show demo examples
252 if [[ $# -eq 0 ]]; then
253 run_demo_examples
254 echo "Continuing with demo execution..."
255 echo
256
257 # Set demo values
258 VERBOSE=true
259 COUNT=2
260 POSITIONAL_ARGS=("demo_file1.txt" "demo_file2.txt" "demo_file3.txt")
261 fi
262
263 # Display parsed configuration
264 display_config
265
266 # Process data based on arguments
267 process_data
268
269 echo -e "${GREEN}=== Processing Complete ===${NC}"
270 echo
271}
272
273main "$@"