在 bash 中测试数字

在 bash 中测试数字

这是测试数字的正确方法吗,在正则表达式周围使用双[[]]引号:digit:和单引号?

if [[ "$var" =~ '^[[:digit:]]+$' ]]; then

答案1

事实并非如此,一个简单的测试将向我们展示:

#!/bin/bash

for var in 1 2 3 a b c; do
  if [[ "$var" =~ '^[[:digit:]]+$' ]]; then
    echo "$var is a number"
  else
    echo "$var is NOT a number"
  fi
done

运行上面的命令会产生:

1 is NOT a number
2 is NOT a number
3 is NOT a number
a is NOT a number
b is NOT a number
c is NOT a number

如果您有一个自动运行的编辑器shellcheck,或者您将代码粘贴到https://shellcheck.net/,您将看到以下错误:

Line 4:
        if [[ "$var" =~ '^[[:digit:]]+$' ]]; then
                        ^-- SC2076 (warning): Remove quotes from right-hand side of =~ to match as a regex rather than literally.

这告诉我们我们应该这样写:

#!/bin/bash

for var in 1 2 3 a b c; do
    if [[ "$var" =~ ^[[:digit:]]+$ ]]; then
        echo "$var is a number"
    else
        echo "$var is NOT a number"
    fi
done

其产生:

1 is a number
2 is a number
3 is a number
a is NOT a number
b is NOT a number
c is NOT a number

这记录在bash 手册页:

还可以使用附加二元运算符 =~,其优先级与 == 和 != 相同。使用时,运算符右侧的字符串被视为 POSIX 扩展正则表达式并进行相应的匹配...如果模式的任何部分被引用,则引用的部分将按字面匹配。这意味着引用部分中的每个字符都与其自身匹配,而不具有任何特殊的模式匹配含义。

答案2

取决于你所说的数字是什么意思。0x12, inf, 1.2, -12, ¹²³, , 1e6, 1,000,000, , , 0x123p-5, 6,23都是0b100110根据某些定义的数字数字、 和080199999999999999999999999999999999999是其他一些人的无效数字。

要测试字符串是否由一个或多个 ASCII 十进制数字组成,可以使用:

标准:

valid() {
  case $1 in
    ("" | *[!0123456789]*) false;;
    (*) true;;
  esac
}

或者在 ksh、bash(bash -O extglob使用旧版本)中或zsh -o kshglob

valid() [[ $1 = +([0123456789]) ]]

或者在 bash/ksh93/zsh/yash 中:

valid() [[ $1 =~ ^[0123456789]+$ ]]

valid() [[ $1 =~ '^[0123456789]+$' ]]也可以在 zsh1 和 bash 3.1 或bash -O compat31.在 中zsh,如果rematchpcre启用了该选项,您需要将其更改为[[ $1 =~ '^[0123456789]\z' ]]$主题末尾的 PCRE 匹配中,但也在主题末尾的换行符之前,以便例如匹配 on $'123\n'。到时候你也可以用[[ $1 =~ '^\d+\z' ]]

zsh

valid() [[ $1 = <-> ]]

无论如何,请避免[[:digit:]]在某些系统上与 ASCII 阿拉伯数字以外的十进制数字匹配。除了在 zsh 中,特别是在 bash 中,不要用于[0-9]输入验证,因为它通常匹配恰好在 0 到 9 之间排序的随机字符。


1 但请注意,在 zsh 中,变量值可以包含 NUL 字节,并且标准 regexp API(与 PCRE 相对)不支持匹配其中包含 NUL 的字符串。当该rematchpcre选项未启用时,[[ $1 =~ '^[0123456789]+$' ]]将匹配$'123\0xyz'例如。

相关内容