【问题标题】:Validate date format in a shell script在 shell 脚本中验证日期格式
【发布时间】:2013-09-11 01:35:58
【问题描述】:

我必须创建一个 Shell 脚本,其中一个参数是 dd/mm/yyyy 格式的日期。我的问题是,如何检查作为参数传递的日期是否真的遵循这种日期格式?我尝试使用 grep 命令如下:

if echo "$1" | grep -q '^[0-3][0-9]/[0-1][0-9]/[0-9]\{4\}$'

但它没有给出正确的格式,因为例如天可以是 33、34、(...),这并不是真正正确的格式。任何人都知道可以真正检查通过的日期是否真的遵循格式 dd/mm/yyyy 的东西?

【问题讨论】:

标签: bash shell date unix if-statement


【解决方案1】:

使用date

date "+%d/%m/%Y" -d "09/99/2013" > /dev/null  2>&1
 is_valid=$?

日期字符串必须是“MM/DD/YYYY”格式。

如果您没有得到 0,则日期格式无效。

【讨论】:

  • 感谢您的回答。这确实有效,但仅适用于 mm/dd/yyyy 格式。如果您在终端上检查选项 -d,只检查格式 mm/dd/yyyy。我尝试更改格式,但它不会影响使用选项 -d for date 命令的方式。
  • WTF?问题是how can I check if the Date passed as parameter really follows this Date Format。这不检查任何东西。 date 接受不同格式的日期。例如tomorrow 是有效格式,date -d 'tomorrow + 5 months 20:00:01 也是有效的。
  • 另外date -d '05/20/1900' 会为我抛出错误。它还取决于您的架构(64 位系统的日期范围可能更大)。这绝对不是要走的路。请改用konsolebox's answer
  • @Aleks-DanielJakimenko 第二个答案同样糟糕,接受像 33/19/2000 这样的日期
  • 正如 Aleks-Daniel Jakimenko-A. 所指出的,这实际上并没有检查日期格式。要验证 dd 是否为 YYYY-MM-DD 格式并且是有效日期,可以执行以下操作: [[ $(date "+%Y-%m-%d" -d "$dd") == "$dd " ]] || echo '无效的日期格式'
【解决方案2】:

最简单但仍能完美运行的解决方案如下:

if [[ $1 =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] && date -d "$1" >/dev/null 2>&1
   ...

它包含两个检查:

  • 第一部分检查$1 是这种格式:NNNN-NN-NN
  • 第二部分检查日期是否有效

您需要这两项检查,因为:

  • 如果您不进行第一次检查,date 会以代码 0 退出,即使您的变量是另一种格式的有效日期
  • 如果您不进行第二次检查,那么即使对于诸如2016-13-45 之类的变量,您最终也会得到 0

【讨论】:

  • 如果您不使用破折号,第二次检查将成功。例如20203112 date -d check 会成功。
【解决方案3】:

这个函数需要两个字符串,一个格式字符串,一个日期字符串

格式字符串使用日期命令中的代码,但不包括“+”

如果提供的日期与给定的格式匹配,该函数返回 0,否则返回 1

代码 (my_script.sh)

#!/bin/bash

datecheck() {
    local format="$1" d="$2"
    [[ "$(date "+$format" -d "$d" 2>/dev/null)" == "$d" ]]
}

date_test="$1"

echo $date_test
if datecheck "%d %b %Y" "$date_test"; then
    echo OK
else
    echo KO
fi

输出

$ ./my_script.sh "05 Apr 2020"
05 Apr 2020
OK
$ ./my_script.sh "foo bar"
foo bar
KO

【讨论】:

  • 这是一个很好的答案!
【解决方案4】:

首先,使用正则表达式检查输入的形式。然后使用 awk 切换到 mm/dd/yyyy 并使用 date 进行验证。您可以在 if 语句中使用以下表达式:

echo "$1" | egrep -q '^[0-3][0-9]/[0-1][0-9]/[0-9]{4}$' && date -d "$(echo "$1" | awk 'BEGIN{FS=OFS="/"}{print $2"/"$1"/"$3}')" >/dev/null 2>&1

【讨论】:

    【解决方案5】:

    dd/mm/yyyy 在 Bash 中的最简单方法是:

    if [[ $1 == [0-3][0-9]/[0-1][0-9]/[0-9][0-9][0-9][0-9] ]]
    

    或者

    if [[ $1 =~ ^[0-3][0-9]/[0-1][0-9]/[0-9]{4}$ ]]
    

    【讨论】:

    • 这正是 OP 所说的没有工作,因为它接受像 33/19/2000 这样的无效日期。
    • @augurar 是的,我本可以制作一个更准确的。但话又说回来,即使是公认的解决方案也可以接受其他格式,而不仅仅是dd/mm/yyyy。所以我相信现在这并不重要。
    【解决方案6】:

    awk怎么样:

    echo "31/12/1999" | awk  -F '/' '{ print ($1 <= 31 && $2 <= 12 && match($3, /^[1-9][1-9][1-9][1-9]$/)) ? "good" : "bad" }'
    

    如果它的有效日期打印“好”,否则打印“坏”

    【讨论】:

    • 这将验证日期,如31/02/201229/02/200131/04/2000 或... :(
    • 我需要跨多个文件验证多种日期格式,我已经准备好获取日期了。该解决方案比 KonsoleBox 或 PxL 更符合要求。话虽如此,请求中日期的格式与此解决方案不同。应该是 echo "31/12/1999" | awk -F '/' '{ print ($1 &lt;= 12 &amp;&amp; $2 &lt;= 31 &amp;&amp; match($3, /^[1-9][1-9][1-9][1-9]$/)) ? "good" : "bad" }' 唯一需要注意的是 02/30/2014 会过去,即使那不是约会,但这仍然非常适合我的需求。
    • 对于年份参数,最好使用[0-9],而不是[1-9]
    【解决方案7】:
    #! /bin/bash
    
    isDateInvalid()
    {
        DATE="${1}"
    
        # Autorized separator char ['space', '/', '.', '_', '-']
        SEPAR="([ \/._-])?"
    
        # Date format day[01..31], month[01,03,05,07,08,10,12], year[1900..2099]
        DATE_1="((([123][0]|[012][1-9])|3[1])${SEPAR}(0[13578]|1[02])${SEPAR}(19|20)[0-9][0-9])"
    
        # Date format day[01..30], month[04,06,09,11], year[1900..2099]
        DATE_2="(([123][0]|[012][1-9])${SEPAR}(0[469]|11)${SEPAR}(19|20)[0-9][0-9])"
    
        # Date format day[01..28], month[02], year[1900..2099]
        DATE_3="(([12][0]|[01][1-9]|2[1-8])${SEPAR}02${SEPAR}(19|20)[0-9][0-9])"
    
        # Date format day[29], month[02], year[1904..2096]
        DATE_4="(29${SEPAR}02${SEPAR}(19|20(0[48]|[2468][048]|[13579][26])))"
    
        # Match the date in the Regex
    
        if ! [[ "${DATE}" =~ "^(${DATE_1}|${DATE_2}|${DATE_3}|${DATE_4})$" ]]
        then
            echo -e "ERROR - '${DATE}' invalid!"
        else
            echo "${DATE} is valid"
        fi
    }
    
    echo
    echo "Exp 1: "`isDateInvalid '12/13/3000'`
    echo "Exp 2: "`isDateInvalid '12/11/2014'`
    echo "Exp 3: "`isDateInvalid '12 01 2000'`
    echo "Exp 4: "`isDateInvalid '28-02-2014'`
    echo "Exp 5: "`isDateInvalid '12_02_2002'` 
    echo "Exp 6: "`isDateInvalid '12.10.2099'`
    echo "Exp 7: "`isDateInvalid '31/11/2000'`
    

    【讨论】:

      【解决方案8】:

      这是一个用来做一些数据验证的函数:

      # Script expecting a Date parameter in MM-DD-YYYY format as input
      verifyInputDate(){
          echo ${date} | grep '^[0-9][0-9]-[0-9][0-9]-[0-9][0-9][0-9][0-9]$'
          if [ $? -eq 0 ]; then
               echo "Date is valid"
           else
                echo "Date is not valid"
           fi
      }
      

      【讨论】:

      • 这并不比 OP 的例子好。像 99/87/0000 这样的日期会通过你的 grep。
      【解决方案9】:

      `X="2016-04-21" 然后检查下面的值是 1 还是 0。

      cal echo $x | cut -c 6-7 echo $x | cut -c 1-4 2>/dev/null | grep -c echo $x | cut -c 9-10

      如果值为1,则有效,否则无效。

      【讨论】:

      • 你的意思是“反引号”吗?那么你应该在你的答案中输入它们,否则它将不起作用,因为目前它们 单引号。
      【解决方案10】:

      虽然解决方案(如果 [[ $1 =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] && date -d "$1" >/dev/null 2>&1) of @https://stackoverflow.com/users/2873507/vic-seedoubleyew 至少对于 linux 来说是最好的,但它会给出错误,因为我们不能在 if 语句中直接比较/匹配正则表达式。我们应该将正则表达式放在一个变量中,然后我们应该在 if 语句中比较/匹配该变量。而且if条件的第二部分没有返回布尔值,所以这部分也会导致错误。

      所以我对上面的公式做了一些小修改,这个修改也可以进一步定制为各种其他格式或它们的组合。

      DATEVALUE=2019-11-12
      REGEX='^[0-9]{4}-[0-9]{2}-[0-9]{2}$'
      if [[ $DATEVALUE =~ $REGEX ]] ; then
          date -d $DATEVALUE 
        if [ $? -eq 0 ] ; then
          echo "RIGHT DATE"
         else 
          echo "WRONG DATE"
        fi
      else
       echo "WRONG FORMAT"
      fi
      

      【讨论】:

        【解决方案11】:

        我编写了这个 bash 脚本来验证日期。我可以接受 mont 作为字母数字。

        #!/bin/bash
        
        function isDateValid {
            DATE=$1
        
            if [[ $DATE =~ ^[0-9]{1,2}-[0-9a-zA-Z]{1,3}-[0-9]{4}$ ]]; then
                echo "Date $DATE is a number!"
                day=`echo $DATE | cut -d'-' -f1`
                month=`echo $DATE | cut -d'-' -f2`
                year=`echo $DATE | cut -d'-' -f3`
        
                        if [ "$month" == "01" ] || [ "$month" == "1" ]; then
                                month="Jan"
                        elif [ "$month" == "02" ] || [ "$month" == "2" ]; then
                                month="Feb"
                        elif [ "$month" == "03" ] || [ "$month" == "3" ]; then
                                month="Mar"
                        elif [ "$month" == "04" ] || [ "$month" == "4" ]; then
                                month="Apr"
                        elif [ "$month" == "05" ] || [ "$month" == "5" ]; then
                                month="May"
                        elif [ "$month" == "06" ] || [ "$month" == "6" ]; then
                                month="Jun"
                        elif [ "$month" == "07" ] || [ "$month" == "7" ]; then
                                month="Jul"
                        elif [ "$month" == "08" ] || [ "$month" == "8" ]; then
                                month="Aug"
                        elif [ "$month" == "09" ] || [ "$month" == "9" ]; then
                                month="Sep"
                        elif [ "$month" == "10" ]; then
                                month="Oct"
                        elif [ "$month" == "11" ]; then
                                month="Nov"
                        elif [ "$month" == "12" ]; then
                                month="Dec"
                        fi
        
                ymd=$year"-"$month"-"$day
                echo "ymd: "$ymd
                dmy=$(echo "$ymd" | awk -F- '{ OFS=FS; print $3,$2,$1 }')
                echo "dmy: "$dmy
                if date --date "$dmy" >/dev/null 2>&1; then
                        echo "OK"
                    return 0
                else
                        echo "NOK"
                    return 1
                fi
            else
                echo "Date $DATE is not a number"
                return 1
            fi
        }
        
        
        if isDateValid "15-15-2014"; then
            echo "date is valid =)"
        else
            echo "bad format date"
        fi
        echo "==================="
        if isDateValid "15-12-2014"; then
                echo "date is valid =)"
        else
                echo "bad format date"
        fi
        echo "==================="
        if isDateValid "15-Dec-2014"; then
                echo "date is valid =)"
        else
                echo "bad format date"
        fi
        echo "==================="
        if isDateValid "1-May-2014"; then
                echo "date is valid =)"
        else
                echo "bad format date"
        fi
        echo "==================="
        if isDateValid "1-1-2014"; then
                echo "date is valid =)"
        else
                echo "bad format date"
        fi
        echo "==================="
        if isDateValid "12-12-2014"; then
                echo "date is valid =)"
        else
                echo "bad format date"
        fi
        

        【讨论】:

          【解决方案12】:

          我想给出一个稍微不同的格式的扩展答案,但这可以很容易地更改为 dd/mm/YY 格式,并且已经给出了答案;它在busybox(posix shell)上测试过

          这是类似于“busybox posix shell 脚本日期”和“测试格式”或“验证”等的网络搜索的第一个热门,所以这里是我的 busybox 解决方案(使用 1.29.3、1.23.1 测试)

          #!/bin/sh
          
          ##########
          #
          # check if date valid in busybox
          #   tested in busybox 1.29.3, 1.23.1
          #
          # call with:
          #   $0 <yyyymmdd>
          #
          ##########
          
          mydate=$1
          
          if echo $mydate | grep -qE '20[0-9][0-9](0[1-9]|1[0-2])([012][0-9]|3[01])'; then
              printf 'may be valid\n'
          
              date +%Y%m%d -d $mydate -D %Y%m%d > /dev/null  2>&1
              is_valid=$?
              if [ $is_valid != 0 ]; then
                  printf 'not valid\n'
                  return 1
              else
                  mytestdate=$(date +%Y%m%d -d $mydate -D %Y%m%d)
                  if [ $mydate != $mytestdate ]; then
                      printf 'not valid, results in "%s"\n' "$mytestdate"
                      return 1
                  else
                      printf 'valid\n'
                  fi
              fi
          else
              printf 'not valid (must be: <yyyymmdd>)\n'
              return 1
          fi
          

          就像在busybox(1.29.3 & 1.23.1)中一样,你的回复如下:

          lxsys:~# date +%Y%m%d -d 20110229 -D "%Y%m%d"
          20110301
          

          我需要以更好的方式验证日期,但我想主要依靠系统本身

          所以

          mytestdate=$(date +%Y%m%d -d $mydate -D %Y%m%d)
          if [ $mydate != $mytestdate ]; then
              ...
          fi
          

          还有第二个测试——我们想要的或给定的格式(输入,$mydate)和它的系统解释(输出,$mytestdate)之间是否有区别......如果不一样,丢弃日期

          【讨论】:

            【解决方案13】:

            块引用

            DATE = "$*"
            
            [[ "${DATE}" != @(((([123][0]|[012][1-9])|3[1])?([ \/._-])(0[13578]|1[02])?([ \/._-])(19|20)[0-9][0-9])|(([123][0]|[012][1-9])?([ \/._-])\
            (0[469]|11)?([ \/._-])(19|20)[0-9][0-9])|(([12][0]|[01][1-9]|2[1-8])?([ \/._-])02?([ \/._-])(19|20)[0-9][0-9])|(29?([ \/._-])02?([ \/._-])\
            (19|20(0[48]|[2468][048]|[13579][26])))) ]] && echo error || echo good)
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-11-22
              • 1970-01-01
              • 1970-01-01
              • 2023-03-14
              • 1970-01-01
              • 1970-01-01
              • 2010-11-26
              • 2017-04-04
              相关资源
              最近更新 更多