检查 bash 中的日期格式

检查 bash 中的日期格式

我在 bash 脚本中有以下几行:

 while true; do
    DATE=date
    FORMAT="%Y%m%d"
    read -p "Enter start date (YYYYMMDD)  " STARTDATE
    if date=$(date -d "$STARTDATE" +'+%Y%m%d'); then
       start_date=`$DATE +$FORMAT -d $STARTDATE`
       echo $start_date
       break
    fi
    echo "Please use right format (YYYYMMDD)  "
 done

只要输入是 8 个数字(例如,它接受“20210901”并拒绝“20213131”),此方法就可以正常工作。然而,当输入完全关闭时(例如“a”或“废话”),它只需要今天的日期。如何修改代码以更严格地检查格式?

修改后的代码如下:

 valid=0
 while true; do
    DATE=date
    FORMAT="%Y%m%d"
    read -p "Enter start date (YYYYMMDD)  " initialdate
    if date=$(date -d "$initialdate" +'+%Y%m%d'); then
       start_date=`$DATE +$FORMAT -d $initialdate`
       if [[ "$start_date" =~ ^[[0123456789]]{8}$ ]]
       then
         valid=1 
         echo "valid"; 
         echo $start_date
         break
       else
         echo "Invalid format" 
       fi
    fi
    echo "Please use right format (YYYYMMDD)  "
 done

答案1

进行输入验证的常见方法是使用无限循环,一旦输入得到验证,您就可以打破该循环。

在这种情况下,“已验证”意味着输入字符串仅包含八位数字,并且 GNUdate能够使用该日期作为其-d选项的选项参数。

有了bash,我们可以把它写成

while true; do
    read -r -p 'Input date: '

    if [[ $REPLY =~ ^[[:digit:]]{8}$ ]] && date -d "$REPLY" >/dev/null 2>&1
    then
        break
    fi

    echo 'Invalid format, try again' >&2
done

thedate=$REPLY

这会读取循环开始时的日期,然后使用正则表达式对其进行测试,如果字符串仅包含八位数字,则该正则表达式将匹配。如果该测试通过,则还会使用 GNU 测试该字符串date。如果进展顺利,循环将通过break语句退出。

在 中sh,我们需要将正则表达式匹配替换为 shell 模式匹配:

while true; do
    printf 'Input date: ' >&2
    read -r REPLY

    case $REPLY in
        *[![:digit:]]*)
            ;;
        ????????)
            date -d "$REPLY" >/dev/null 2>&1 && break
    esac

    echo 'Invalid format, try again' >&2
done

thedate=$REPLY

这里的测试首先测试字符串是否包含数字以外的任何其他字符。如果该测试失败,则下一次测试恰好是八个字符。如果测试成功,我们将得到一个八位数字的字符串,我们使用 GNU 进行测试date,如果日期正确则退出循环。

答案2

由于您可以将任务简化为额外的检查,要求输入恰好包含 8 位数字,并且您使用的是 Bash,因此您可以利用正则表达式比较运算符:

if [[ "$startdate" =~ ^[0123456789]{8}$ ]]; then echo "valid"; else echo "invalid"; fi

这将检查 的内容是否$startdate符合恰好由八位数字组成的正则表达式。

您可以将其组合如下:

valid=0
while (( valid == 0 )); do
    valid=1
    IFS= read -r -p "Enter start date (YYYYMMDD): " startdate

    if [[ ! "$startdate" =~ ^[0123456789]{8}$ ]]; then valid=0;
    elif ! date -d "$startdate" +%Y%m%d > /dev/null 2>&1 ; then valid=0; fi

    if (( valid == 0 )); then printf "Invalid date entered\n"; fi
done

# < ... operations for valid date here ... >

作为基本规则:

  • 推荐使用shellcheck,也可作为许多 Linux 发行版上的独立程序来验证您的 shell 脚本。
  • 不鼓励使用全大写的变量名称,除非您想将它们导出为环境变量,以避免$PATH意外覆盖关键设置。

答案3

或者没有无限循环,并假设 BSD 的date(1)命令:

REPLY=
valid=false

while ! $valid; do

    read -r -p 'Input date: '

    if ([[ $REPLY =~ ^[[:digit:]]{8}$ ]]) && (date -j +%Y%m%d ${REPLY}0000 >/dev/null 2>&1)
    then
        valid=true
    else
        echo 'Invalid format, try again' >&2
    fi

done

thedate=$REPLY

${REPLY}0000语法是必要的,因为 BSDdate需要完整的 YmdHM,但默认 HM 就0000足够了。

相关内容