Bash Functions: Regular Expressions Exercises and Solutions
1.
Matching Emails:
Write a bash script that creates a regular expression to match email addresses. Test it with different email formats to ensure it captures variations like [email protected] or [email protected].
Code:
#!/bin/bash
# Regular expression for email validation
regex="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
# Test cases
emails=(
"[email protected]"
"[email protected]"
"[email protected]"
"[email protected]"
"[email protected]"
"[email protected]"
"invalid-email@com"
"@example.com"
"[email protected]"
"user@com."
)
# Function to test the regex against each email
function test_email {
local email=$1
if [[ $email =~ $regex ]]; then
echo "$email - Match"
else
echo "$email - No Match"
fi
}
Output:
dt@DESKTOP-3KE0KU4:~$ ./test1.sh [email protected] - Match [email protected] - Match [email protected] - Match [email protected] - Match [email protected] - Match [email protected] - Match invalid-email@com - No Match @example.com - No Match [email protected] - No Match user@com. - No Match
Explanation:
In the exercise above,
- Regular expression definition:
- The variable 'regex' is defined to store the regular expression for email validation.
- Test cases:
- An array 'emails' is created to hold various email addresses to be tested against the regex.
- Function definition:
- test_email function:
- Takes an email address as an argument.
- Checks if the email matches the regex.
- Prints "Match" if the email is valid, otherwise prints "No Match".
- Loop Through Emails:
- Iterates over each email in the 'emails' array.
- Calls the "test_email()" function for each email.
2.
Finding Phone Numbers:
Write a bash script that creates a regular expression to find phone numbers in various formats, including international formats like +1 (555) 123-4567 and local formats like 555-123-4567.
Code:
#!/bin/bash
# Regular expression for phone number validation
regex="^(\+?[0-9]{1,3}[-.\s]?)?(\(?[0-9]{3}\)?[-.\s]?)?[0-9]{3}[-.\s]?[0-9]{4}$"
# Test cases
phone_numbers=(
"+1 (555) 123-4567"
"555-123-4567"
"+44 20 7946 0958"
"+91-9876543210"
"123 456 7890"
"(123) 456-7890"
"123.456.7890"
"+49 30 123456"
"5551234567"
"1-800-123-4567"
"18001234567"
"123-45-6789" # Invalid case (too short)
"123-456-78901" # Invalid case (too long)
)
# Function to test the regex against each phone number
function test_phone_number {
local phone_number=$1
if [[ $phone_number =~ $regex ]]; then
echo "$phone_number - Match"
else
echo "$phone_number - No Match"
Output:
dt@DESKTOP-3KE0KU4:~$ ./test1.sh +1 (555) 123-4567 - No Match 555-123-4567 - Match +44 20 7946 0958 - No Match +91-9876543210 - Match 123 456 7890 - No Match (123) 456-7890 - No Match 123.456.7890 - Match +49 30 123456 - No Match 5551234567 - Match 1-800-123-4567 - Match 18001234567 - Match 123-45-6789 - No Match 123-456-78901 - No Match
Explanation:
In the exercise above,
- Regular expression definition:
- The variable 'regex' is defined to store the regular expression for phone number validation. The 'regex' handles optional international codes, various delimiters (spaces, dots, hyphens), and different phone number formats.
- Test cases:
- An array 'phone_numbers' is created to hold various phone numbers to be tested against the regex.
- Function definition:
- test_phone_number function:
- Take a phone number as an argument.
- Check if the phone number matches the 'regex'.
- Prints "Match" if the phone number is valid, otherwise prints "No Match".
- Loop through Phone numbers:
- Iterates over each phone number in the 'phone_numbers' array.
- Calls the "test_phone_number()" function for each phone number.
3.
Extracting URLs:
Write a bash script to extract URLs using 'regex' from a block of text. Test it with different URL formats, including HTTP and HTTPS protocols, with or without www, and with query parameters.
Code:
#!/bin/bash
# Regular expression for URL extraction
regex='(https?:\/\/(www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}([\/?][^\s]*)?)'
# Block of text containing URLs
text="
Here are some URLs:
- https://www.example.com
- http://example.com
- https://example.co.uk/path?query=param
- http://www.example.org/test
- https://subdomain.example.net
- http://example.com/path/to/resource
- https://example.com?name=value&key=123
Visit https://www.another-example.com for more info.
Check out this site: http://example.io
"
# Extract and print URLs
while [[ $text =~ $regex ]]; do
echo "${BASH_REMATCH[0]}"
text=${text#*"${BASH_REMATCH[0]}"}
done
Output:
rg@DESKTOP-3KE0KU4:~$ ./test1.sh https://www.example.com http://example.com https://example.co.uk/path?query=param - http://www.example.org/te https://subdomain.example.net http://example.com/path/to/re https://example.com?name=value&key=123 Vi https://www.another-example.com http://example.iod
Explanation:
In the exercise above,
- Regular expression definition:
- The variable 'regex' is defined to store the regular expression for URL extraction. The regex captures URLs starting with 'http' or 'https', optionally followed by 'www', a domain name, and optionally a path or query string.
- Block of text:
- The variable 'text' contains a block of text with various URL formats.
- Extract and print URLs:
- The 'while' loop iterates over the block of text, matching URLs using the 'regex'.
- ${BASH_REMATCH[0]} captures the entire URL matched by the regex.
- The matched URL is printed.
- The text is updated to remove the already matched URL, allowing the loop to find subsequent URLs.
4.
Parsing Dates:
Write a Bash script to develop a regular expression to parse dates in different formats, such as MM/DD/YYYY, YYYY-MM-DD, or written out like January 1, 2019.
Code:
#!/bin/bash
# Regular expressions for different date formats
regex_mm_dd_yyyy="([0-1]?[0-9])\/([0-2]?[0-9]|3[01])\/([0-9]{4})"
regex_yyyy_mm_dd="([0-9]{4})-([0-1]?[0-9])-([0-2]?[0-9]|3[01])"
regex_written_out="([Jj]anuary|[Ff]ebruary|[Mm]arch|[Aa]pril|[Mm]ay|[Jj]une|[Jj]uly|[Aa]ugust|[Ss]eptember|[Oo]ctober|[Nn]ovember|[Dd]ecember) ([0-2]?[0-9]|3[01]), ([0-9]{4})"
# Block of text containing dates in various formats
text="
Here are some dates:
- 12/25/2023
- 2024-05-20
- March 15, 2021
- 01/01/2020
- 1999-12-31
- February 29, 2020
- 10/31/2021
- 2022-11-11
"
# Function to extract and print dates based on a regex
function extract_dates {
local regex=$1
local text=$2
while [[ $text =~ $regex ]]; do
echo "${BASH_REMATCH[0]}"
text=${text#*"${BASH_REMATCH[0]}"}
done
}
# Extract dates in MM/DD/YYYY format
echo "Dates in MM/DD/YYYY format:"
extract_dates "$regex_mm_dd_yyyy" "$text"
# Extract dates in YYYY-MM-DD format
echo "Dates in YYYY-MM-DD format:"
extract_dates "$regex_yyyy_mm_dd" "$text"
# Extract dates in written-out format
echo "Dates in written-out format:"
extract_dates "$regex_written_out" "$text"
Output:
ad@DESKTOP-3KE0KU4:~$ ./test1.sh Dates in MM/DD/YYYY format: 12/25/2023 01/01/2020 10/31/2021 Dates in YYYY-MM-DD format: 2024-05-20 1999-12-31 2022-11-11 Dates in written-out format: March 15, 2021 February 29, 2020
Explanation:
In the exercise above,
- Regular Expression Definitions:
- regex_mm_dd_yyyy: Matches dates in 'MM/DD/YYYY' format. It handles one or two-digit months and days, and four-digit years.
- regex_yyyy_mm_dd: Matches dates in 'YYYY-MM-DD' format. It handles one or two-digit months and days, and four-digit years.
- regex_written_out: Matches dates in written-out format, such as 'January 1, 2019'. It considers month names in both uppercase and lowercase, one or two-digit days, and four-digit years.
- Block of Text:
- The variable 'text' contains a block of text with various date formats.
- Function to Extract Dates:
- extract_dates function:
- Takes a regex and a block of text as arguments.
- Uses a "while" loop to iterate over the text and match dates using the regex.
- Prints each matched date.
- Updates the text to remove the already matched date, allowing the loop to find subsequent dates.
- Extract and Print Dates:
- The script calls 'extract_dates' for each date format (MM/DD/YYYY, YYYY-MM-DD, and written-out) and prints the results.
5.
Validating Passwords:
Write a Bash script to create a regex to validate passwords based on certain criteria, such as minimum length, requiring both uppercase and lowercase letters, numbers, and special characters.
Code:
#!/bin/bash
# List of passwords to test
passwords=(
"Password123!" # Valid
"pass123!" # Invalid (no uppercase)
"PASSWORD123!" # Invalid (no lowercase)
"Password!" # Invalid (no number)
"Password123" # Invalid (no special character)
"P@ssw0rd" # Valid
"StrongP@ssw0rd" # Valid
"WeakPassword123" # Invalid (no special character)
"1234!@#$" # Invalid (no letters)
"Valid123@Pass" # Valid
"Pas1#" # InValid (length less than 8)
)
# Regular expression for password validation
regex='^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[@$!%*?&]).{8,}$'
# Function to validate passwords using grep -P
validate_password() {
local password=$1
# Debugging output to check the password being tested
echo "Testing password: '$password'"
if echo "$password" | grep -P "$regex" >/dev/null; then
echo "Password '$password' is VALID."
else
echo "Password '$password' is INVALID."
fi
}
# Loop through each password and validate it
for password in "${passwords[@]}"; do
validate_password "$password"
done
Output:
dt@DESKTOP-3KE0KU4:~$ ./test1.sh Testing password: 'Password123!' Password 'Password123!' is VALID. Testing password: 'pass123!' Password 'pass123!' is INVALID. Testing password: 'PASSWORD123!' Password 'PASSWORD123!' is INVALID. Testing password: 'Password!' Password 'Password!' is INVALID. Testing password: 'Password123' Password 'Password123' is INVALID. Testing password: 'P@ssw0rd' Password 'P@ssw0rd' is VALID. Testing password: 'StrongP@ssw0rd' Password 'StrongP@ssw0rd' is VALID. Testing password: 'WeakPassword123' Password 'WeakPassword123' is INVALID. Testing password: '1234!@#$' Password '1234!@#$' is INVALID. Testing password: 'Valid123@Pass' Password 'Valid123@Pass' is VALID. Testing password: 'Pas1#' Password 'Pas1#' is INVALID.
Explanation:
In the exercise above,
- Shebang: #!/bin/bash specifies the script should be run with the Bash shell.
- Password List: A list of passwords that contain a variety of test passwords.
- Password Validation Regex: "regex" is defined to match passwords that:
- Have at least one lowercase letter.
- Have at least one uppercase letter.
- Have at least one digit.
- Have at least one special character from the set @$!%*?&.
- Are at least 8 characters long.
- Validation Function: validate_password:
- Takes a password as an argument.
- Prints the password being tested.
- Use grep -P to match the password against the regex.
- Prints whether the password is VALID or INVALID based on the match result.
- Loop Through Passwords: Iterates over each password in the passwords array and calls validate_password for each one.
Bash Editor:
More to Come !
Do not submit any solution of the above exercises at here, if you want to contribute go to the appropriate exercise page.
- Weekly Trends and Language Statistics
- Weekly Trends and Language Statistics