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.



Follow us on Facebook and Twitter for latest update.