如何根据 Bash 版本/功能编写条件代码?

How to write conditional code depending on Bash version / features?

我在我的 Bash 脚本之一中使用了 =~。但是,我需要使脚本与不支持该运算符的 Bash 版本兼容,特别是 msysgit which is not build against libregex 附带的 Bash 版本。我有一个使用 expr match 的解决方法,但由于某种原因,它在 Mac OS X 上再次不起作用。

因此,我只想使用 expr match if [ -n "$MSYSTEM" -a ${BASH_VERSINFO[0]} -lt 4 ],否则使用 =~。问题是 Bash 似乎总是解析整个脚本,即使 msysgit Bash 会在运行时执行解决方法,它在解析脚本时仍然会偶然发现 =~

是否可以根据 Bash 版本在同一脚本中有条件地执行代码,或者我应该寻找另一种方法来解决这个问题?

我目前的解决方案是在所有平台上使用 grep -q。这避免了任何条件或复杂的代码结构。

可能仅在运行时使用 eval 来解析包含 =~ 的代码也可行,但话又说回来,这会使代码更难阅读。

对于您的情况,您可以用等效的模式匹配替换正则表达式。

[[ $foo = \[+([0-9])\][[:space:]]* ]]

一些解释:

  • 模式与整个字符串匹配。以下正则表达式和模式是等效的:

    1. ^foo$foo
    2. ^foofoo*
    3. foo$*foo
    4. foo*foo*
  • +(...) 匹配封闭模式的一次或多次出现,在本例中为 [0-9]。也就是说,如果 $pattern$regex 匹配相同的字符串,那么 +($pattern)($regex)+.

对于这个特定的模式,可以阐明等效但可移植的 case 语句。不过,它需要有相当多的不同 glob 模式来枚举所有极端情况。

case $foo in
  [![]*  | \[[!0-9]* | *[!][0-9[:space:]]* | *[!0-9[:space:]] | \
  *\]*[![:space:]] | *[!0-9]\]* | \[*\[* | *\]*\]* )
    return 1;;  # false
  \[*[0-9]*\]* )
    return 0;;  # true
  *)
    return 1;;  # false
esac