Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if a string matches a regex in Bash script

People also ask

How do you check if a string matches a regex in bash?

You can use the test construct, [[ ]] , along with the regular expression match operator, =~ , to check if a string matches a regex pattern (documentation). where commands after && are executed if the test is successful, and commands after || are executed if the test is unsuccessful.

How do you check if a regex matches a string?

Use the test() method to check if a regular expression matches an entire string, e.g. /^hello$/. test(str) . The caret ^ and dollar sign $ match the beginning and end of the string. The test method returns true if the regex matches the entire string, and false otherwise.

Can you use regex in bash?

Regex is a very powerful tool that is available at our disposal & the best thing about using regex is that they can be used in almost every computer language. So if you are Bash Scripting or creating a Python program, we can use regex or we can also write a single line search query.

What does =~ mean in bash?

A regular expression matching sign, the =~ operator, is used to identify regular expressions. Perl has a similar operator for regular expression corresponding, which stimulated this operator.


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

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"

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

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

Reference: http://tldp.org/LDP/abs/html/bashver3.html#REGEXMATCHREF

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


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') ] 

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;

Main code

# Define arguments for the function to test

regex_v='^[0-9]*$'; # Regex rule
value_1_v='12345'; # First value
value_2_v='67890'; # Second value
# A statement which runs the function with specified arguments
# and executes `printf 'Valid';` if succeeded, else - `printf 'Invalid';`

if RT "$regex_v" "$value_v";

It should be possible to point at failed argument, for example, by appending a counter in loop and printing its value to stderr.

Related

The quotes around the right-hand side of the =~ operator cause it to become a string, rather than a RegularExpression.

Source