Check If a String Matches a Regex in Bash Script

One of the arguments that my script receives is a date in the following format: yyyymmdd.

I want to check if I get a valid date as an input.

How can I do this? I am trying to use a regex like: [0-9]\{\8}

1

5 Answers

You can use the test construct, [[ ]], along with the regular expression match operator, =~, to check if a string matches a regex pattern (documentation).

For your specific case, you can write:

[[ "$date" =~ ^[0-9]{8}$ ]] && echo "yes"

Or more a accurate test:

[[ "$date" =~ ^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$ ]] && echo "yes"
#             |\______/\______*______/\______*__________*______/|
#             |   |           |                  |              |
#             |   |           |                  |              |
#             | --year--   --month--           --day--          |
#             |          either 01...09      either 01..09      |
#      start of line         or 10,11,12         or 10..29      |
#                                                or 30, 31      |
#                                                          end of line

That is, you can define a regex in Bash matching the format you want. This way you can do:

[[ "$date" =~ ^regex$ ]] && echo "matched" || echo "did not match"

where commands after && are executed if the test is successful, and commands after || are executed if the test is unsuccessful.

Note this is based on the solution by Aleks-Daniel Jakimenko in User input date format verification in bash.


In other shells you can use grep. If your shell is POSIX compliant, do

(echo "$date" | grep -Eq  ^regex$) && echo "matched" || echo "did not match"

In fish, which is not POSIX-compliant, you can do

echo "$date" | grep -Eq "^regex\$"; and echo "matched"; or echo "did not match"

Caveat: These portable grep solutions are not water-proof! For example, they can be tricked by input parameters that contain newlines. The first mentioned bash-specific regex check does not have this issue.

19

In bash version 3 you can use the '=~' operator:

if [[ "$date" =~ ^[0-9]{8}$ ]]; then
    echo "Valid date"
else
    echo "Invalid date"
fi

Reference:

NOTE: The quoting in the matching operator within the double brackets, [[ ]], is no longer necessary as of Bash version 3.2

0

A good way to test if a string is a correct date is to use the command date:

if date -d "${DATE}" >/dev/null 2>&1
then
  # do what you need to do with your date
else
  echo "${DATE} incorrect date" >&2
  exit 1
fi

from comment: one can use formatting

if [ "2017-01-14" == $(date -d "2017-01-14" '+%Y-%m-%d') ] 
7

In addition to other answers of the =~ Bash operator - Extended Regular Expressions (ERE).

This is the syntax used by awk and egrep (or grep -E),
as well as by Bash's [[ ... =~ ... ]] operator.

For example, a function which supports multiple test provided in multiple arguments:

#!/bin/bash

#-----------#
# Functions #
#-----------#

function RT
{
    declare line_l;

    for line_l in "${@:2}";
    do
        if ! [[ "$line_l" =~ $1 ]];
        then
            return 1;
        fi
    done

    return 0;
}

#-----------#
# Main      #
#-----------#

regex_v='^[0-9]*$';
value_1_v='12345';
value_2_v='67890';

if RT "$regex_v" "$value_1_v" "$value_2_v";
then
    printf 'Valid';
else
    printf 'Invalid';
fi

Description

Function RT or Regex Test

# Declare a local variable for a loop.

declare line_l;
# Loop for every argument's value except the first whish is a regex rule

for line_l in "${@:2}";
# Test the value and return a **non-zero** return code if failed

if ! [[ "$line_l" =~ $1 ]];
# Return a **zero** return code - success.

return 0;
Elena Rostova

Elena Rostova

Lead Health, Wellness & Medical Journalist

Elena Rostova holds a Master's degree in Public Health Journalism. She covers groundbreaking medical research, holistic wellness trends, mental health awareness, and nutritional science.