/ bin / dash:检查$ 1是否为数字


12

检查$ 1是否为/ bin / dash中的整数的最佳方法是什么?

用bash,我可以做:

[[ $1 =~ ^([0-9]+)$ ]]

但这似乎不符合POSIX,并且破折号不支持该功能

Answers:


12

以下检测正整数或负整数,并在dash和下工作,它们是POSIX:

选项1

echo "$1" | grep -Eq '^[+-]?[0-9]+$' && echo "It's an integer"

选项2

case "${1#[+-]}" in
    ''|*[!0-9]*)
        echo "Not an integer" ;;
    *)
        echo "Integer" ;;
esac

或者,仅使用:(nop)命令:

! case ${1#[+-]} in *[!0-9]*) :;; ?*) ! :;; esac && echo Integer

5
如果字符串包含换行符怎么办?foo\n123\nbar不是整数,但可以通过此测试。
godlygeek

3
grep版本,即。案例版本看起来正确。
godlygeek

5

是否dashbashkshzsh,POSIX sh,或posh“Bourne Shell的重新实现” sh); 该case构造是使用最广泛且最可靠的:

case $1 in (*[!0-9]*|"") false ;; (*) true ;; esac

你在下面测试过dash吗?它对我有效bash但不起作用dash
John1024

是的,我也使用dash;询问我echo $?在case命令之后添加的结果。
Janis

我做了同样的事情(Debian稳定版),但是没有喜悦。有关在破折号下对我有用的完整示例,请参阅我的选项2
John1024

嗯,我没有原始的bourne外壳可供测试。我检查过的文档“至少在bourne shell中没有[ksh]功能”没有提及,因此我认为它在那里。没有?-然后省略开头的括号。-OTOH posh(“ Bourne外壳的重新实现”)对该解决方案也没有问题。
Janis

1
@mikeserv; 为什么在其中使用始终匹配的括号有几个原因case:一个原因是您所描述的错误,另一个原因是在具有依赖于匹配括号(vim)的功能的编辑器中,它提供了更好的支持,并且我个人更容易识别它们的匹配,这尤其是显而易见。-WRT posh为POSIX;好吧,我在手册页上引述的内容提出了其他建议,但我想,无论如何也不能依赖这样的非正式声明。既然我们处在POSIX时代,那么旧的bourne shell就不再那么重要了。
Janis

1

您可以-eq对字符串本身使用测试:

$ dash -c 'a="a"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi' 
dash: 1: [: Illegal number: a
not a number
$ dash -c 'a="0xa"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
dash: 1: [: Illegal number: 0xa
not a number
$ dash -c 'a="-1"; if [ "$a" -eq "$a" ] ; then echo number; else echo not a number; fi'
number

如果错误消息有问题,请将错误输出重定向到/dev/null

$ dash -c 'a="0xa"; [ "$a" -eq "$a" ] 2>/dev/null|| echo no'
no

1
它还会说这" 023 "是一个数字。请注意,它适用于破折号,但不适用于所有其他POSIX shell,因为如果操作数为注释十进制整数,则行为未指定。例如,使用ksh时,会说SHLVL或是1+1一个数字。
斯特凡Chazelas

0

尝试将其用作算术扩展,并查看其是否有效。实际上,您需要严格一点,因为例如算术扩展会忽略前导和尾随空格。因此,请进行算术扩展,并确保扩展后的结果与原始变量完全匹配。

check_if_number()
{
    if [ "$1" = "$((${1}))" ] 2>/dev/null; then
        echo "Number!"
    else
        echo "not a number"
    fi
}

这也将接受负数-如果您确实要排除它们,请为添加一个额外的支票$((${1} >= 0))


1
破折号没有[[
glenn jackman 2015年

@glennjackman哎呀。有$(( ... ))吗?如果是这样,我的答案应该仍然是正确的,我只需要添加一些额外的引号即可。
godlygeek

您的答案就是:找出答案。
glenn jackman 2015年

看起来确实如此,所以我的更新版本应该可以解决问题。不过,我没有破折号进行测试-因此,如果我错过了其他任何内容,请告诉我。
godlygeek

我尝试过:check_if_number 1.2函数返回: dash: 3: arithmetic expression: expecting EOF: "1.2"
John1024

0

也许与expr

if expr match "$1" '^\([0-9]\+\)$' > /dev/null; then
  echo "integer"
else 
  echo "non-integer"
fi

既不match也不\+是POSIX。它还会说0不是数字。你想expr "x$1" : 'x[0-9]\{1,\}$'
斯特凡Chazelas

0

在POSIX系统中,可以使用expr

$ a=a
$ expr "$a" - 0 >/dev/null 2>&1
$ [ "$?" -lt 2 ] && echo Integer || echo Not Integer

它会说0不是整数(并且说-12是OP的bash解决方案将拒绝的值)。一些expr实现将说9999999999999999999不是整数。POSIX不提供任何保证。实际上,至少在GNU系统上,它将说“长度”是一个整数。
斯特凡Chazelas

在我的测试中,它至少在Debian和OSX中有效。它的确表示0的整数。Posix确保$ a必须是expr do算术的有效表达式(整数)。
cuonglm 2015年

哦,是的,对不起,我忽略了您的$测试?<2仍然expr 9999999999999999999 + 0给了我3退出状态expr -12 + 0,并expr length + 0给我用GNU EXPR 0退出状态(+ stringstring被视为与GNU字符串exprexpr "$a" - 0会更好地工作)。
斯特凡Chazelas

@StéphaneChazelas:哦,是的,更新了我的答案。我认为-12是一个有效的整数,并9999999999999999999给溢出了。
cuonglm

0

这是一个简单的函数,使用与muru的答案相同的方法:

IsInteger()      # usage: IsInteger string
{               #  returns: flag
        [ "$1" -eq "$1" ] 2> /dev/null
}

例:

p= n=2a3; IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"
p= n=23;  IsInteger $n || p="n't" ; printf "'%s' is%s an integer\n" "$n" "$p"

输出:

'2a3' isn't an integer
'23' is an integer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.