我的脚本接收的参数之一是一个日期,格式如下:yyyymmdd。

我想检查我是否得到了一个有效的日期作为输入。

我该怎么做呢?我试图使用一个正则表达式,如:[0-9]\{\8}


当前回答

正则表达式的使用有助于确定日期的字符序列是否正确,但它不能轻易用于确定日期是否有效。下面的例子将传递正则表达式,但都是无效日期:20180231,20190229,20190431

因此,如果您想验证日期字符串(我们称其为datestr)是否具有正确的格式,最好使用date解析它,并要求date将字符串转换为正确的格式。如果两个字符串相同,则具有有效格式和有效日期。

if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
     echo "Valid date"
else
     echo "Invalid date"
fi

其他回答

在bash版本3中,你可以使用'=~'操作符:

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

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

注意:在双括号内的匹配操作符[[]]中,从Bash版本3.2开始不再需要引号

您可以使用测试结构[[]]以及正则表达式匹配操作符=~来检查字符串是否与正则表达式模式匹配(文档)。

对于你的具体情况,你可以这样写:

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

或者更准确的测试:

[[ "$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

也就是说,您可以在Bash中定义与所需格式相匹配的正则表达式。你可以这样做:

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

如果测试成功,执行&&后的命令;如果测试不成功,执行||后的命令。

注意,这是基于Aleks-Daniel Jakimenko在bash中的用户输入日期格式验证中的解决方案。


在其他shell中,您可以使用grep。如果您的shell是POSIX兼容的,那么就这样做

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

在fish中,它不符合posix,你可以这样做

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

警告:这些便携式grep解决方案不防水!例如,它们可以被包含换行符的输入参数欺骗。第一个提到的特定于bash的正则表达式检查没有这个问题。

除了=~ Bash操作符的其他答案-扩展正则表达式(ERE)。

这是awk和egrep(或grep -E)使用的语法, 以及Bash的[[…]= ~…]]。

例如,在多个参数中提供支持多重测试的函数:

#!/bin/bash

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

function RT
{
    declare __line;

    for __line in "${@:2}";
    do
        if ! [[ "$__line" =~ $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

描述

函数RT或正则表达式测试

# Declare a local variable for a loop.

declare __line;
# Loop for every argument's value except the first - regex rule

for __line in "${@:2}";
# Test the value and return a **non-zero** return code if failed.
# Alternative: if [[ ! "$__line" =~ $1 ]];

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

return 0;

主要代码

# 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";

应该可以指向失败的参数,例如,通过在循环中附加一个计数器并将其值打印到stderr。

相关的

=~操作符右边的引号导致它变成一个字符串,而不是一个正则表达式。 源

正则表达式的使用有助于确定日期的字符序列是否正确,但它不能轻易用于确定日期是否有效。下面的例子将传递正则表达式,但都是无效日期:20180231,20190229,20190431

因此,如果您想验证日期字符串(我们称其为datestr)是否具有正确的格式,最好使用date解析它,并要求date将字符串转换为正确的格式。如果两个字符串相同,则具有有效格式和有效日期。

if [[ "$datestr" == $(date -d "$datestr" "+%Y%m%d" 2>/dev/null) ]]; then
     echo "Valid date"
else
     echo "Invalid date"
fi

一个测试字符串是否为正确日期的好方法是使用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

注释:可以使用格式

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