尝试在 bash 条件 statement/case 中使用通配符与精确的 alpha 字符混合并失败

Trying to use wildcards in bash conditional statement/case mixed with exact alpha char and failing

本质上,我正在测试一个变量以确保它的内容匹配特定的时间格式:4 位数字,am/pm/AM/PM,没有空格(即 1204pm)。我已经完成了这么多工作:

tm0=1204pm; [[ $tm0 == [0-2###aApP]* ]] && echo PASS

tm0=1203pm; case $tm0 in [0-2###apAP]*) echo PASS; esac

但是当我尝试将最后一个字符指定为 "m" 时(最初我尝试指定 [Mm] 但那也不起作用)它失败了。

tm0=1204pm; [[ $tm0 == [0-2###aApP]m ]] && echo PASS

任何帮助,谢谢。

bash 模式不是正则表达式。它们也不是 Java 模式,我认为这就是您要使用的模式(尽管一点也不清楚)。

您可以(并且应该)阅读 bash manual chapter on pattern matching,这是模式特征的完整列表。在那里,你会看到:

  • [...] 匹配单个字符,该字符是封闭字符 class 描述

  • 中的字符之一
  • * 匹配任意数量的任意字符

所以[0-2###apAP]*匹配其中一个字符0,1,2, #, a,p, A,或 P,后跟任意数量的字符(包括 0)。

我想你要找的是:

[01][0-9][0-5][0-9][aApP][mM]

虽然这有点大方,因为它会匹配,例如 1300pm ("It was a bright cold day in April, and the clocks were striking thirteen.")

使用 globs:

[[ $tm0 == [01][0-9][0-5][0-9][aApP][mM] ]]

请注意,这将验证,例如 1900pm。如果你不想这样:

[[ $tm0 == @(0[0-9]|1[0-2])[0-5][0-9][aApP][mM] ]]

这使用 extended globs. Note that you don't need shopt -s extglob to use extended globs inside [[ ... ]]: in section Condition Constructs,有关 [[ ... ]] 的文档您可以阅读:

When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below in Pattern Matching, as if the extglob shell option were enabled.

要在 case 语句中使用此功能,您需要启用 extglob.


使用正则表达式:

[[ $tm0 =~ ^(0[0-9]|1[0-2])([0-5][0-9])([aApP][mM])$ ]]

通过这些分组,您可以在 BASH_REMATCH[0] 中得到小时,在 BASH_REMATCH[1] 中得到分钟,在 BASH_REMATCH[2] 中得到 am/pm。