我正在尝试做一些常见的事情:在shell脚本中解析用户输入。如果用户提供了有效的整数,则脚本会执行一项操作,如果无效,则执行其他操作。麻烦的是,我还没有找到一种简单(而且相当优雅)的方式 - 我不想用char来分开char。
我知道这一定很容易,但我不知道怎么做。我可以用十几种语言来做,但不是BASH!
在我的研究中,我发现了这个:
Regular expression to test whether a string consists of a valid real number in base 10
其中有一个关于正则表达式的答案,但据我所知,这是C中的一个函数(等等)。尽管如此,它看起来像是一个很好的答案,所以我用grep尝试了它,但是grep不知道该怎么做。我试过-P在我的盒子上意味着把它当作PERL regexp - nada。 Dash E(-E)也没有用。而且-F。
也没有为了清楚起见,我正在尝试这样的事情,寻找任何输出 - 从那里,我将破解脚本以利用我得到的任何东西。 (IOW,我希望在有效行重复时,不符合要求的输入不会返回任何内容。)
snafu=$(echo "$2" | 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
有人请说明这是最容易做到的吗?
坦率地说,在我看来,这是TEST的缩影。它应该有这样的标志
if [ -I "string" ] ;
then
echo "String is a valid integer."
else
echo "String is not a valid integer."
fi
答案 0 :(得分:166)
[[ $var =~ ^-?[0-9]+$ ]]
^
表示输入模式的开头-
是文字“ - ”?
表示“前一个(-
)”中的0或1 +
表示“前面的一个或多个([0-9]
)”$
表示输入模式的结束因此正则表达式匹配可选的-
(对于负数的情况),后跟一个或多个十进制数字。
<强>参考强>:
答案 1 :(得分:59)
-eq
一个班轮是最酷的。
我正在运行GNU bash,版本4.1.5
(Debian)。我也在ksh上检查了这个(SunSO 5.10)。
以下是我的检查$1
是否为整数的版本:
if [ "$1" -eq "$1" ] 2>/dev/null
then
echo "$1 is an integer !!"
else
echo "ERROR: first parameter must be an integer."
echo $USAGE
exit 1
fi
这种方法也考虑了负数,其他一些解决方案会产生错误的否定结果,并且它将允许前缀为“+”(例如+30),这显然是一个整数。
结果:
$ 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.
Ignacio Vazquez-Abrams提供的解决方案在解释之后也非常整洁(如果你喜欢正则表达式)。但是,它不会使用+
前缀处理正数,但可以轻松修复如下:
[[ $var =~ ^[-+]?[0-9]+$ ]]
答案 2 :(得分:25)
此次聚会的迟到者。我非常惊讶,没有一个答案提到最简单,最快,最便携的解决方案; case
声明。
case ${variable#[-+]} in
*[!0-9]* | '') echo Not a number ;;
* ) echo Valid number ;;
esac
在比较之前修剪任何符号感觉有点像黑客,但这使得case语句的表达式变得更加简单。
答案 3 :(得分:9)
对于预先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 : REGEX
搜索在STRING开始时锚定的REGEX,回显第一组(或匹配的长度,如果没有)并返回成功/失败。这是旧的正则表达式语法,因此超出\
。 -\?
表示“可能-
”,[0-9]\+
表示“一个或多个数字”,$
表示“字符串结束”。
Bash也支持扩展的全局,但我不记得从哪个版本开始。
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])) ]]
@(-|)
表示“-
或无”,[0-9]
表示“数字”,*([0-9])
表示“零或更多数字”。
答案 4 :(得分:8)
我喜欢使用-eq
测试的解决方案,因为它基本上是一行的。
我自己的解决方案是使用参数扩展来丢弃所有数字并查看是否还有其他内容。 (我还在使用3.0,之前没有使用[[
或expr
,但很高兴见到它们。)
if [ "${INPUT_STRING//[0-9]}" = "" ]; then
# yes, natural number
else
# no, has non-numeral chars
fi
答案 5 :(得分:3)
这是另一个问题(仅使用test builtin命令及其返回码):
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
答案 6 :(得分:2)
您可以删除非数字并进行比较。这是一个演示脚本:
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
这是测试输出的样子:
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
答案 7 :(得分:2)
对我来说,最简单的解决方案是在(())
表达式中使用变量,如下所示:
if ((VAR > 0))
then
echo "$VAR is a positive integer."
fi
当然,只有零值对您的应用程序没有意义时,此解决方案才有效。在我的情况下,这恰好是正确的,这比其他解决方案简单得多。
正如评论中所指出的,这会使您受到代码执行攻击:(( ))
运算符评估VAR
,如the bash(1) man page Arithmetic Evaluation
部分所述}。因此,当VAR
的内容来源不确定时,您不应该使用此技术(当然,您也不应该使用任何其他形式的变量扩展)。
答案 8 :(得分:0)
或使用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
答案 9 :(得分:0)
添加Ignacio Vazquez-Abrams的答案。这将允许+符号在整数之前,并且它将允许任意数量的零作为小数点。例如,这将允许+45.00000000被视为整数 但是,$ 1必须格式化为包含小数点。这里45不算是整数,但45.0是。
if [[ $1 =~ ^-?[0-9]+.?[0]+$ ]]; then
echo "yes, this is an integer"
elif [[ $1 =~ ^\+?[0-9]+.?[0]+$ ]]; then
echo "yes, this is an integer"
else
echo "no, this is not an integer"
fi
答案 10 :(得分:0)
对于笑声,我大致只是快速计算出一组函数来执行此操作(is_string,is_int,is_float,是字符串或其他),但是有更高效(更少代码)的方法来执行此操作:
#!/bin/bash
function strindex() {
x="${1%%$2*}"
if [[ "$x" = "$1" ]] ;then
true
else
if [ "${#x}" -gt 0 ] ;then
false
else
true
fi
fi
}
function is_int() {
if is_empty "${1}" ;then
false
return
fi
tmp=$(echo "${1}" | sed 's/[^0-9]*//g')
if [[ $tmp == "${1}" ]] || [[ "-${tmp}" == "${1}" ]] ; then
#echo "INT (${1}) tmp=$tmp"
true
else
#echo "NOT INT (${1}) tmp=$tmp"
false
fi
}
function is_float() {
if is_empty "${1}" ;then
false
return
fi
if ! strindex "${1}" "-" ; then
false
return
fi
tmp=$(echo "${1}" | sed 's/[^a-z. ]*//g')
if [[ $tmp =~ "." ]] ; then
#echo "FLOAT (${1}) tmp=$tmp"
true
else
#echo "NOT FLOAT (${1}) tmp=$tmp"
false
fi
}
function is_strict_string() {
if is_empty "${1}" ;then
false
return
fi
if [[ "${1}" =~ ^[A-Za-z]+$ ]]; then
#echo "STRICT STRING (${1})"
true
else
#echo "NOT STRICT STRING (${1})"
false
fi
}
function is_string() {
if is_empty "${1}" || is_int "${1}" || is_float "${1}" || is_strict_string "${1}" ;then
false
return
fi
if [ ! -z "${1}" ] ;then
true
return
fi
false
}
function is_empty() {
if [ -z "${1// }" ] ;then
true
else
false
fi
}
在这里运行一些测试,我定义-44是一个int但是44-不是等..:
for num in "44" "-44" "44-" "4-4" "a4" "4a" ".4" "4.4" "-4.4" "09" "hello" "h3llo!" "!!" " " "" ; do
if is_int "$num" ;then
echo "INT = $num"
elif is_float "$num" ;then
echo "FLOAT = $num"
elif is_string "$num" ; then
echo "STRING = $num"
elif is_strict_string "$num" ; then
echo "STRICT STRING = $num"
else
echo "OTHER = $num"
fi
done
输出:
INT = 44
INT = -44
STRING = 44-
STRING = 4-4
STRING = a4
STRING = 4a
FLOAT = .4
FLOAT = 4.4
FLOAT = -4.4
INT = 09
STRICT STRING = hello
STRING = h3llo!
STRING = !!
OTHER =
OTHER =
注意:在添加八进制等数字时,前导0可能会推断其他内容,因此如果您打算将'09'视为int(我正在做),最好将其剥离(例如expr 09 + 0
或用sed剥离)