w3resource

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.



Become a Patron!

Follow us on Facebook and Twitter for latest update.

It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.

https://w3resource.com/bash-script-exercises/regular-expressions.php