1#!/usr/bin/env bash
2set -euo pipefail
3
4# Input Validation Using Bash Regex
5# Demonstrates various validation patterns using bash's =~ operator and BASH_REMATCH
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 NC='\033[0m' # No Color
16
17# ============================================================================
18# Validation Functions
19# ============================================================================
20
21# Validate email address format
22validate_email() {
23 local email="$1"
24
25 # Email regex: local-part@domain.tld
26 # Simplified pattern for demonstration
27 local email_regex='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
28
29 if [[ "$email" =~ $email_regex ]]; then
30 # BASH_REMATCH[0] contains the entire match
31 echo -e "${GREEN}✓${NC} Valid email: $email"
32 return 0
33 else
34 echo -e "${RED}✗${NC} Invalid email: $email"
35 return 1
36 fi
37}
38
39# Validate IPv4 address
40validate_ipv4() {
41 local ip="$1"
42
43 # IPv4 regex with capturing groups for each octet
44 local ip_regex='^([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$'
45
46 if [[ ! "$ip" =~ $ip_regex ]]; then
47 echo -e "${RED}✗${NC} Invalid IPv4 format: $ip"
48 return 1
49 fi
50
51 # Check each octet is in valid range (0-255)
52 # BASH_REMATCH[1-4] contain the four octets
53 local octet
54 for i in 1 2 3 4; do
55 octet="${BASH_REMATCH[$i]}"
56 if [[ $octet -gt 255 ]]; then
57 echo -e "${RED}✗${NC} Invalid IPv4 (octet $octet > 255): $ip"
58 return 1
59 fi
60 done
61
62 echo -e "${GREEN}✓${NC} Valid IPv4: $ip (octets: ${BASH_REMATCH[1]}.${BASH_REMATCH[2]}.${BASH_REMATCH[3]}.${BASH_REMATCH[4]})"
63 return 0
64}
65
66# Validate date in YYYY-MM-DD format with range checks
67validate_date() {
68 local date_str="$1"
69
70 # Date regex with capturing groups for year, month, day
71 local date_regex='^([0-9]{4})-([0-9]{2})-([0-9]{2})$'
72
73 if [[ ! "$date_str" =~ $date_regex ]]; then
74 echo -e "${RED}✗${NC} Invalid date format: $date_str (expected YYYY-MM-DD)"
75 return 1
76 fi
77
78 local year="${BASH_REMATCH[1]}"
79 local month="${BASH_REMATCH[2]}"
80 local day="${BASH_REMATCH[3]}"
81
82 # Basic range validation
83 if [[ $month -lt 1 || $month -gt 12 ]]; then
84 echo -e "${RED}✗${NC} Invalid month: $month (must be 01-12)"
85 return 1
86 fi
87
88 if [[ $day -lt 1 || $day -gt 31 ]]; then
89 echo -e "${RED}✗${NC} Invalid day: $day (must be 01-31)"
90 return 1
91 fi
92
93 if [[ $year -lt 1900 || $year -gt 2100 ]]; then
94 echo -e "${YELLOW}⚠${NC} Date year out of typical range: $year"
95 fi
96
97 echo -e "${GREEN}✓${NC} Valid date: $date_str (Y=$year, M=$month, D=$day)"
98 return 0
99}
100
101# Validate semantic version (e.g., 1.2.3, 2.0.0-beta, 1.0.0+build123)
102validate_semver() {
103 local version="$1"
104
105 # Semantic versioning regex: major.minor.patch[-prerelease][+buildmetadata]
106 local semver_regex='^([0-9]+)\.([0-9]+)\.([0-9]+)(-([a-zA-Z0-9.-]+))?(\+([a-zA-Z0-9.-]+))?$'
107
108 if [[ ! "$version" =~ $semver_regex ]]; then
109 echo -e "${RED}✗${NC} Invalid semver: $version"
110 return 1
111 fi
112
113 local major="${BASH_REMATCH[1]}"
114 local minor="${BASH_REMATCH[2]}"
115 local patch="${BASH_REMATCH[3]}"
116 local prerelease="${BASH_REMATCH[5]}"
117 local build="${BASH_REMATCH[7]}"
118
119 echo -e "${GREEN}✓${NC} Valid semver: $version"
120 echo " Major: $major, Minor: $minor, Patch: $patch"
121 [[ -n "$prerelease" ]] && echo " Prerelease: $prerelease"
122 [[ -n "$build" ]] && echo " Build: $build"
123
124 return 0
125}
126
127# Validate URL (http/https)
128validate_url() {
129 local url="$1"
130
131 # URL regex with protocol, host, optional port, optional path
132 local url_regex='^(https?)://([a-zA-Z0-9.-]+)(:[0-9]+)?(/[^[:space:]]*)?$'
133
134 if [[ ! "$url" =~ $url_regex ]]; then
135 echo -e "${RED}✗${NC} Invalid URL: $url"
136 return 1
137 fi
138
139 local protocol="${BASH_REMATCH[1]}"
140 local host="${BASH_REMATCH[2]}"
141 local port="${BASH_REMATCH[3]}"
142 local path="${BASH_REMATCH[4]}"
143
144 echo -e "${GREEN}✓${NC} Valid URL: $url"
145 echo " Protocol: $protocol"
146 echo " Host: $host"
147 [[ -n "$port" ]] && echo " Port: ${port:1}" # Remove leading colon
148 [[ -n "$path" ]] && echo " Path: $path"
149
150 return 0
151}
152
153# ============================================================================
154# Demo Section
155# ============================================================================
156
157demo_email_validation() {
158 echo -e "\n${BLUE}=== Email Validation ===${NC}\n"
159
160 local -a test_emails=(
161 "user@example.com"
162 "john.doe+tag@company.co.uk"
163 "invalid@"
164 "@example.com"
165 "no-at-sign.com"
166 "test@domain"
167 "valid.email@subdomain.example.com"
168 )
169
170 for email in "${test_emails[@]}"; do
171 validate_email "$email"
172 done
173}
174
175demo_ipv4_validation() {
176 echo -e "\n${BLUE}=== IPv4 Validation ===${NC}\n"
177
178 local -a test_ips=(
179 "192.168.1.1"
180 "10.0.0.1"
181 "255.255.255.255"
182 "256.1.1.1"
183 "192.168.1"
184 "192.168.1.1.1"
185 "0.0.0.0"
186 )
187
188 for ip in "${test_ips[@]}"; do
189 validate_ipv4 "$ip"
190 done
191}
192
193demo_date_validation() {
194 echo -e "\n${BLUE}=== Date Validation ===${NC}\n"
195
196 local -a test_dates=(
197 "2024-01-15"
198 "2024-12-31"
199 "2024-13-01"
200 "2024-01-32"
201 "24-01-15"
202 "2024/01/15"
203 "1850-06-15"
204 )
205
206 for date in "${test_dates[@]}"; do
207 validate_date "$date"
208 done
209}
210
211demo_semver_validation() {
212 echo -e "\n${BLUE}=== Semantic Version Validation ===${NC}\n"
213
214 local -a test_versions=(
215 "1.0.0"
216 "2.5.13"
217 "1.0.0-alpha"
218 "1.0.0-beta.1"
219 "1.0.0+20240115"
220 "1.0.0-rc.1+build.456"
221 "v1.0.0"
222 "1.0"
223 )
224
225 for version in "${test_versions[@]}"; do
226 validate_semver "$version"
227 done
228}
229
230demo_url_validation() {
231 echo -e "\n${BLUE}=== URL Validation ===${NC}\n"
232
233 local -a test_urls=(
234 "https://example.com"
235 "http://localhost:8080"
236 "https://api.example.com/v1/users"
237 "https://sub.domain.example.com:443/path?query=1"
238 "ftp://example.com"
239 "example.com"
240 "http://"
241 )
242
243 for url in "${test_urls[@]}"; do
244 validate_url "$url"
245 done
246}
247
248# ============================================================================
249# Main Execution
250# ============================================================================
251
252main() {
253 echo -e "${BLUE}╔════════════════════════════════════════════╗${NC}"
254 echo -e "${BLUE}║ Input Validation with Bash Regex Demo ║${NC}"
255 echo -e "${BLUE}╚════════════════════════════════════════════╝${NC}"
256
257 demo_email_validation
258 demo_ipv4_validation
259 demo_date_validation
260 demo_semver_validation
261 demo_url_validation
262
263 echo -e "\n${GREEN}=== All Validation Demos Complete ===${NC}\n"
264}
265
266main "$@"