我想检查 shell 脚本的参数是否为整数(即非负整数:0、1、2、3、…、17、…、42、…等,但不是 3.1416 或 −5 )以十进制表示(所以不像 0x11 或 0x2A)。如何使用正则表达式作为条件(以匹配数字)编写 case 语句?我尝试了几种不同的方法(例如,[0-9]+
或^[0-9][0-9]*$
);它们都不起作用。如下例所示,有效数字通过旨在捕获它们的数字正则表达式并与通配符匹配 *
。
i=1
let arg_n=$#+1
while (( $i < $arg_n )); do
case ${!i} in
[0-9]+)
n=${!i}
;;
*)
echo 'Invalid argument!'
;;
esac
let i=$i+1
done
输出:
$ ./cmd.sh 64
Invalid argument!
答案1
答案2
正如格伦所说, “case
不使用正则表达式,它使用图案”。作为重击(1)说,
case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
A
case
命令首先展开word
,并尝试将其与每个匹配pattern
反过来,使用与路径名扩展相同的匹配规则(请参阅路径名扩展以下)。
相似地,POSIX 规范说,
… 每个图案…应与扩展进行比较单词,根据中描述的规则模式匹配表示法 ……
所以图案是路径名扩展模式,又名通配符,又名通配符,如ls -l -- *.sh
或中的rm -- *.bak
。
当然,shopt -s extglob
和[[ … =~ … ]]
是自切片面包以来最简洁的东西,但它们不是 POSIX,了解如何使用原始工具可能会很有用。例如,多年来,程序员通过检查字符串是否为数字来检查字符串是否为数字。不是一个号码。您已将数字定义为(全部)由一位或多位数字组成的字符串。因此,如果字符串为空,或者包含非数字字符,则该字符串不是数字。我们可以使用case
如下语句来测试这些条件:
case "$1" in
("")
# null
︙
;;
(*[!0-9]*)
# contains non-numeric character(s)
︙
;;
(*)
# is a whole number (non-negative integer)
︙
esac
其中[!0-9]
是旧式 shell 的表达方式[^0-9]
,当然,它表示除数字之外的任何字符。 ([!…]
两者[^…]
都在 bash 中工作。POSIX
[!…]
需要工作;其结果[^…]
未指定。)如果您不关心字符串是哪种非数字,则可以组合非数字模式:
case "$1" in
("" | *[!0-9]*)
# not a number
︙
;;
(*)
# is a number
︙
esac
作为练习,这里有一个case
处理任何类型实数的语句 - 准确地说,是一个由一个或多个数字组成的字符串,可选地在某处带有句点 ( ),并且可选地在开头带有.
减号 ( )。-
case "$1" in
(*[!-.0-9]*)
# contains non-numeric character(s)
;;
(*?-*)
# contains '-' somewhere other than the first position
;;
(*.*.*)
# contains multiple decimal points
;;
(*)
case "$1" in
(*[0-9]*)
# is a real number
;;
(*)
# not a number
esac
esac
我添加了case
-within-a-case
来验证该字符串确实至少包含一位数字。在整数示例中这不是必需的,因为我测试了字符串是否为空;我已从本声明中删除了一项测试。如果没有第二个case
,单个-
或单个.
- 甚至-.
- 将有资格作为数字。当然,我们可以添加模式来处理这些异常,但这可能会变得复杂。 (例如,我几乎发布了这个答案,但没有意识到这-.
是例外之一。)我相信上述方法更加灵活和稳健。
当然,非数字模式也可以在这里组合:
(*[!-.0-9]* | *?-* | *.*.*)
。
答案3
到case
在语句中使用正则表达式匹配数字,您需要一个通配符支持正则表达式的 shell。我只知道 ksh93 与这些。
使用 ksh93 glob,您可以在 glob 模式中执行~(E)^[0-9]+$
或~(E:^[0-9]+$)
使用扩展正则表达式,或者使用类似 perl 的正则表达式(也适用于基本正则表达式、增强正则表达式、SysV 正则表达式)。E
~(P)^\d+$
G
X
V
所以:
#! /bin/ksh93 -
for i do
case $i in
(~(E)^[0-9]+$)
n=$i;;
(*)
echo >&2 'Invalid argument!'
usage
esac
done