我想测试一个变量是否有超过 4 位这样的数字
#!/bin/bash
if [ $input has more than 4 digits ]; then
echo " * Please only 4 digits" >&2
echo""
else
the other option
fi
Run Code Online (Sandbox Code Playgroud)
这里假设您的意思是 ASCII 十进制数字,而不是其他类型的十进制或非十进制数字。
shopt -s extglob # enables a subset of ksh extended globs including *(...),
# +(...) and ?(...) but unfortunately not {4}(...)
d='[0123456789]' nd='[^0123456789]'
case $input in
( $d$d$d$d+($d) ) echo made of more than 4 digits;;
( *$d*$d*$d*$d*$d* ) echo contains more than 4 digits;;
( "" ) echo empty;;
( *($nd) ) echo does not contain any digit;;
( *$nd* ) echo no more than 4 digits but also contains non-digits;;
( $d?($d)?($d)?($d) ) echo made of 1 to 4 digits;;
( * ) echo should not be reached;;
esac
Run Code Online (Sandbox Code Playgroud)
请注意,bash
取决于系统和语言环境,[0-9]
并且[[:digit:]]
可能匹配的不仅仅是 0123456789,因此不应将它们用于输入验证(例如,在对不同问题的回答中有更多内容)。
还要注意bash
模式匹配在多字节语言环境中以非常令人惊讶的方式工作。
您会发现,例如在zh_CN.gb18030
中文语言环境中,input='1-©©'
它会no more than 4 digits but also contains non-digits
按预期返回,但是如果附加一个0x80
字节 ( input='1-©©'$'\x80'
),它将返回contains more than 4 digits
.
正是出于这种原因(以及已知模式匹配在许多 shell 中的极端情况下存在错误这一事实),对于输入验证,最好对您接受的事物尽可能使用正匹配(而不是负匹配)对于要拒绝的事物)¹ 因此$d?($d)?($d)?($d)
,即使至少在理论上它不是必需的,但其他任何东西都应该与早期的模式相匹配。
¹ 作为例外,人们可能需要考虑 Bourne 和 Korn shell 的错误特征,即case $input in [x]) echo yes; esac
匹配x
但也匹配[x]
!
我会做
#!/usr/bin/env bash
die () { echo "$*" >&2; exit 1; }
input=$1
[[ $input == +([[:digit:]]) ]] || die "only digits please"
(( input <= 9999 )) || die "no more than 4 digits please"
echo "ok: $input"
Run Code Online (Sandbox Code Playgroud)
如果您关心位数(而不是数值),您可以匹配 Bash/Ksh/Zsh 中的正则表达式(* 见脚注[[:digit:]]
):
#!/bin/bash
input=$1
re='^[[:digit:]]{1,4}$'
if [[ $input =~ $re ]]; then
echo "'$input' contains 1 to 4 digits (and nothing else)"
else
echo "'$input' contains something else"
fi
Run Code Online (Sandbox Code Playgroud)
或者例如[[ $input =~ ^[[:digit:]]{5,}$ ]]
检查“5 位或更多位数字(没有别的)”等。
或者在纯 POSIX shell 中,您必须在其中使用case
模式匹配:
#!/bin/sh
input=$1
case $input in
*[![:digit:]]*) onlydigits=0;; # contains non-digits
*[[:digit:]]*) onlydigits=1;; # at least one digit
*) onlydigits=0;; # empty
esac
if [ $onlydigits = 0 ]; then
echo "'$input' is empty or contains something other than digits"
elif [ "${#input}" -le 4 ]; then
echo "'$input' contains 1 to 4 digits (and nothing else)"
else
echo "'$input' contains 5 or more digits (but nothing else)"
fi
Run Code Online (Sandbox Code Playgroud)
(你可以把所有的逻辑放在case
,但嵌套if
那里有点难看,IMO。)
请注意,它[[:digit:]]
应该与当前语言环境的“数字”概念相匹配。这可能会也可能不会超过 ASCII 数字0123456789
。在我的系统上,[[:digit:]]
不匹配,例如?(上标四,U+2074),但[0-9]
确实如此。匹配其他“数字”可能是一个问题,尤其是。如果您对外壳中的数字进行算术运算。因此,如果您想更严格,请使用[0123456789]
仅接受 ASCII 数字。