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}
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}
You can say:
[[ $date =~ ^[0-9]{8}$ ]] && echo "yes"
Or more accurate:
[[ $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 end of line
# start of line or 10,11,12 or 10..29
# or 30, 31
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"
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
I would use expr match
instead of =~
:
expr match "$date" "[0-9]\{8\}" >/dev/null && echo yes
This is better than the currently accepted answer of using =~
because =~
will also match empty strings, which IMHO it shouldn't. Suppose badvar
is not defined, then [[ "1234" =~ "$badvar" ]]; echo $?
gives (incorrectly) 0
, while expr match "1234" "$badvar" >/dev/null ; echo $?
gives correct result 1
.
We have to use >/dev/null
to hide expr match
's output value, which is the number of characters matched or 0 if no match found. Note its output value is different from its exit status. The exit status is 0 if there's a match found, or 1 otherwise.
Generally, the syntax for expr
is:
expr match "$string" "$lead"
Or:
expr "$string" : "$lead"
where $lead
is a regular expression. Its exit status
will be true (0) if lead
matches the leading slice of string
(Is there a name for this?). For example expr match "abcdefghi" "abc"
exits true
, but expr match "abcdefghi" "bcd"
exits false
. (Credit to @Carlo Wood for pointing out this.
Where the usage of a regex can be helpful to determine if the character sequence of a date is correct, it cannot be used easily to determine if the date is valid. The following examples will pass the regular expression, but are all invalid dates: 20180231, 20190229, 20190431
So if you want to validate if your date string (let's call it datestr
) is in the correct format, it is best to parse it with date
and ask date
to convert the string to the correct format. If both strings are identical, you have a valid format and valid date.
if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
echo "Valid date"
else
echo "Invalid date"
fi