string 测试字符串是否为有效整数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2210349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 00:38:31  来源:igfitidea点击:

Test whether string is a valid integer

stringbashif-statementinteger

提问by Richard T

I'm trying to do something common enough: Parse user input in a shell script. If the user provided a valid integer, the script does one thing, and if not valid, it does something else. Trouble is, I haven't found an easy (and reasonably elegant) way of doing this - I don't want to have to pick it apart char by char.

我正在尝试做一些足够常见的事情:在 shell 脚本中解析用户输入。如果用户提供了一个有效的整数,脚本会做一件事,如果无效,它会做其他事情。问题是,我还没有找到一种简单(而且相当优雅)的方法来做到这一点——我不想把它逐个分开。

I know this must be easy but I don't know how. I could do it in a dozen languages, but not BASH!

我知道这一定很容易,但我不知道怎么做。我可以用十几种语言来做,但不能用 BASH!

In my research I found this:

在我的研究中,我发现了这一点:

Regular expression to test whether a string consists of a valid real number in base 10

用于测试字符串是否包含以 10 为底的有效实数的正则表达式

And there's an answer therein that talks about regex, but so far as I know, that's a function available in C (among others). Still, it had what looked like a great answer so I tried it with grep, but grep didn't know what to do with it. I tried -P which on my box means to treat it as a PERL regexp - nada. Dash E (-E) didn't work either. And neither did -F.

其中有一个关于正则表达式的答案,但据我所知,这是 C 中可用的函数(以及其他函数)。尽管如此,它的答案看起来不错,所以我用 grep 尝试了一下,但 grep 不知道如何处理它。我试过 -P 在我的盒子上意味着把它当作一个 PERL 正则表达式 - nada。Dash E (-E) 也不起作用。-F也没有。

Just to be clear, I'm trying something like this, looking for any output - from there, I'll hack up the script to take advantage of whatever I get. (IOW, I was expecting that a non-conforming input returns nothing while a valid line gets repeated.)

为了清楚起见,我正在尝试这样的事情,寻找任何输出 - 从那里,我将修改脚本以利用我得到的任何东西。(IOW,我期望不符合要求的输入在重复有效行时不返回任何内容。)

snafu=$(echo "" | grep -E "/^[-+]?(?:\.[0-9]+|(?:0|[1-9][0-9]*)(?:\.[0-9]*)?)$/")
if [ -z "$snafu" ] ;
then
   echo "Not an integer - nothing back from the grep"
else
   echo "Integer."
fi

Would someone please illustrate how this is most easily done?

有人请说明这是最容易做到的吗?

Frankly, this is a short-coming of TEST, in my opinion. It should have a flag like this

坦率地说,在我看来,这是 TEST 的一个缺点。它应该有一个这样的标志

if [ -I "string" ] ;
then
   echo "String is a valid integer."
else
   echo "String is not a valid integer."
fi

回答by Ignacio Vazquez-Abrams

[[ $var =~ ^-?[0-9]+$ ]]
  • The ^indicates the beginning of the input pattern
  • The -is a literal "-"
  • The ?means "0 or 1 of the preceding (-)"
  • The +means "1 or more of the preceding ([0-9])"
  • The $indicates the end of the input pattern
  • ^表示输入模式的开始
  • -是字符“ - ”
  • ?意思是“0或前述的1(-)”
  • +意思是“1或多个前述的([0-9])”
  • $指示输入图案的端部

So the regex matches an optional -(for the case of negative numbers), followed by one or more decimal digits.

所以正则表达式匹配一个可选的-(对于负数的情况),后跟一个或多个十进制数字。

References:

参考资料

回答by Peter Ho

Wow... there are so many good solutions here!! Of all the solutions above, I agree with @nortally that using the -eqone liner is the coolest.

哇……这里有这么多好的解决方案!!在上述所有解决方案中,我同意 @nortally 的观点,即使用-eq一个衬垫是最酷的。

I am running GNU bash, version 4.1.5(Debian). I have also checked this on ksh (SunSO 5.10).

我正在运行 GNU bash 版本4.1.5(Debian)。我也在 ksh (SunSO 5.10) 上进行了检查。

Here is my version of checking if $1is an integer or not:

这是我检查是否$1为整数的版本:

if [ "" -eq "" ] 2>/dev/null
then
    echo " is an integer !!"
else
    echo "ERROR: first parameter must be an integer."
    echo $USAGE
    exit 1
fi

This approach also accounts for negative numbers, which some of the other solutions will have a faulty negative result, and it will allow a prefix of "+" (e.g. +30) which obviously is an integer.

这种方法也考虑了负数,其他一些解决方案会产生错误的负结果,并且它允许前缀“+”(例如+30),这显然是一个整数。

Results:

结果:

$ int_check.sh 123
123 is an integer !!

$ int_check.sh 123+
ERROR: first parameter must be an integer.

$ int_check.sh -123
-123 is an integer !!

$ int_check.sh +30
+30 is an integer !!

$ int_check.sh -123c
ERROR: first parameter must be an integer.

$ int_check.sh 123c
ERROR: first parameter must be an integer.

$ int_check.sh c123
ERROR: first parameter must be an integer.

The solution provided by Ignacio Vazquez-Abrams was also very neat (if you like regex) after it was explained. However, it does not handle positive numbers with the +prefix, but it can easily be fixed as below:

Ignacio Vazquez-Abrams 提供的解决方案在解释后也非常简洁(如果你喜欢正则表达式)。但是,它不处理带有+前缀的正数,但可以很容易地修复如下:

[[ $var =~ ^[-+]?[0-9]+$ ]]

回答by tripleee

Latecomer to the party here. I'm extremely surprised none of the answers mention the simplest, fastest, most portable solution; the casestatement.

来这里聚会的迟到者。我非常惊讶没有一个答案提到最简单、最快、最便携的解决方案;该case声明。

case ${variable#[-+]} in
  *[!0-9]* | '') echo Not a number ;;
  * ) echo Valid number ;;
esac

The trimming of any sign before the comparison feels like a bit of a hack, but that makes the expression for the case statement so much simpler.

在比较之前修剪任何符号感觉有点像黑客,但这使得 case 语句的表达式变得如此简单。

回答by nortally

I like the solution using the -eqtest, because it's basically a one-liner.

我喜欢使用-eq测试的解决方案,因为它基本上是单行的。

My own solution was to use parameter expansion to throw away all the numerals and see if there was anything left. (I'm still using 3.0, haven't used [[or exprbefore, but glad to meet them.)

我自己的解决方案是使用参数扩展来丢弃所有数字,看看是否还有任何东西。(我现在还在用3.0,没有使用过[[expr之前,但很高兴见到他们。)

if [ "${INPUT_STRING//[0-9]}" = "" ]; then
  # yes, natural number
else
  # no, has non-numeral chars
fi

回答by ephemient

For portability to pre-Bash 3.1 (when the =~test was introduced), use expr.

为了可移植到 Bash 3.1 之前的版本(=~引入测试时),请使用expr.

if expr "$string" : '-\?[0-9]\+$' >/dev/null
then
  echo "String is a valid integer."
else
  echo "String is not a valid integer."
fi

expr STRING : REGEXsearches for REGEX anchored at the start of STRING, echoing the first group (or length of match, if none) and returning success/failure. This is old regex syntax, hence the excess \. -\?means "maybe -", [0-9]\+means "one or more digits", and $means "end of string".

expr STRING : REGEX搜索锚定在 STRING 开头的 REGEX,回显第一组(或匹配长度,如果没有)并返回成功/失败。这是旧的正则表达式语法,因此多余的\. -\?表示“可能-”,[0-9]\+表示“一位或多位数字”,$表示“字符串结尾”。

Bash also supports extended globs, though I don't recall from which version onwards.

Bash 还支持扩展的 glob,但我不记得是从哪个版本开始的。

shopt -s extglob
case "$string" of
    @(-|)[0-9]*([0-9]))
        echo "String is a valid integer." ;;
    *)
        echo "String is not a valid integer." ;;
esac

# equivalently, [[ $string = @(-|)[0-9]*([0-9])) ]]

@(-|)means "-or nothing", [0-9]means "digit", and *([0-9])means "zero or more digits".

@(-|)表示“-或没有”,[0-9]表示“数字”,*([0-9])表示“零个或多个数字”。

回答by hans

Here's yet another take on it (only using the test builtin command and its return code):

这是另一种看法(仅使用 test 内置命令及其返回码):

function is_int() { return $(test "$@" -eq "$@" > /dev/null 2>&1); } 

input="-123"

if $(is_int "${input}");
then
   echo "Input: ${input}"
   echo "Integer: $[${input}]"
else
   echo "Not an integer: ${input}"
fi

回答by Paused until further notice.

You can strip non-digits and do a comparison. Here's a demo script:

您可以去除非数字并进行比较。这是一个演示脚本:

for num in "44" "-44" "44-" "4-4" "a4" "4a" ".4" "4.4" "-4.4" "09"
do
    match=${num//[^[:digit:]]}    # strip non-digits
    match=${match#0*}             # strip leading zeros
    echo -en "$num\t$match\t"
    case $num in
        $match|-$match)    echo "Integer";;
                     *)    echo "Not integer";;
    esac
done

This is what the test output looks like:

这是测试输出的样子:

44      44      Integer
-44     44      Integer
44-     44      Not integer
4-4     44      Not integer
a4      4       Not integer
4a      4       Not integer
.4      4       Not integer
4.4     44      Not integer
-4.4    44      Not integer
09      9       Not integer

回答by Trebor Rude

For me, the simplest solution was to use the variable inside a (())expression, as so:

对我来说,最简单的解决方案是在(())表达式中使用变量,如下所示:

if ((VAR > 0))
then
  echo "$VAR is a positive integer."
fi

Of course, this solution is only valid if a value of zero doesn't make sense for your application. That happened to be true in my case, and this is much simpler than the other solutions.

当然,此解决方案仅在零值对您的应用程序没有意义时才有效。在我的情况下恰好是这样,这比其他解决方案简单得多。

As pointed out in the comments, this can make you subject to a code execution attack: The (( ))operator evaluates VAR, as stated in the Arithmetic Evaluationsection of the bash(1) man page. Therefore, you should not use this technique when the source of the contents of VARis uncertain (nor should you use ANY other form of variable expansion, of course).

正如评论中所指出的,这会使您受到代码执行攻击:(( ))运算符评估VAR,如bash(1) 手册页Arithmetic Evaluation部分所述。因此,当内容的来源VAR不确定时不应使用此技术(当然也不应使用任何其他形式的变量扩展)。

回答by knipwim

or with sed:

或使用 sed:

   test -z $(echo "2000" | sed s/[0-9]//g) && echo "integer" || echo "no integer"
   # integer

   test -z $(echo "ab12" | sed s/[0-9]//g) && echo "integer" || echo "no integer"
   # no integer

回答by JustinMT

Adding to the answer from Ignacio Vazquez-Abrams. This will allow for the + sign to precede the integer, and it will allow any number of zeros as decimal points. For example, this will allow +45.00000000 to be considered an integer.
However, $1 must be formatted to contain a decimal point. 45 is not considered an integer here, but 45.0 is.

添加到 Ignacio Vazquez-Abrams 的答案。这将允许 + 符号位于整数之前,并且允许任意数量的零作为小数点。例如,这将允许将 +45.00000000 视为整数。
但是,$1 的格式必须包含小数点。45 在这里不被视为整数,但 45.0 是。

if [[  =~ ^-?[0-9]+.?[0]+$ ]]; then
    echo "yes, this is an integer"
elif [[  =~ ^\+?[0-9]+.?[0]+$ ]]; then
    echo "yes, this is an integer"
else
    echo "no, this is not an integer"
fi