测试 bash 脚本中变量的位数是否超过 4 位

测试 bash 脚本中变量的位数是否超过 4 位

我想测试一个变量是否超过 4 位数字,如下所示

#!/bin/bash
if [ $input has more than 4 digits ]; then 
     echo "  * Please only 4 digits" >&2
     echo""
else
   the other option
fi

答案1

如果您关心位数(而不是数值),您可以与 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

或者例如[[ $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

(你可以把所有的逻辑都放在 里面case,但是if在我看来,嵌套 那里 有点难看。)


请注意,[[:digit:]]应该与当前区域设置的“数字”概念相匹配。这可能会或可能不会超过 ASCII 数字0123456789。在我的系统上,[[:digit:]]不匹配例如 ⁴(上标四,U+2074),但是[0-9]匹配。匹配其他“数字”可能是一个问题,尤其是。如果你对 shell 中的数字进行算术运算。因此,如果您想更严格,请使用[0123456789]仅接受 ASCII 数字。

答案2

这里假设您仅指 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

请注意,根据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 的极端情况下都存在错误),对于输入验证,最好对您接受的内容尽可能使用正匹配(而不是负匹配)对于要拒绝的事物) 1 因此,$d?($d)?($d)?($d)尽管至少在理论上它不是必需的,但其他任何内容都应该与早期的模式相匹配。


1 作为一个例外,人们可能需要考虑 Bourne 和 Korn shell 的缺陷,即case $input in [x]) echo yes; esac匹配 onx但也匹配[x]!

答案3

我会做

#!/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"

答案4

这是另一种方式:

#!/bin/bash
if test -z "$1"
then
    echo no digit supplied
elif grep -qE '[[:digit:]]{5}' <<< "$1"
then
    echo too many digits supplied
else
    echo number of digits ok
fi

相关内容