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개 이상의 숫자(다른 숫자 없음)" 등을 확인합니다.


case또는 순수 POSIX 셸에서는 패턴 일치를 사용해야 합니다 .

#!/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:]]⁴(위 첨자 4, U+2074)가 일치하지 않지만 [0-9]일치합니다. 다른 "숫자"를 일치시키는 것은 문제가 될 수 있습니다. 쉘의 숫자에 대해 산술 연산을 수행하는 경우. 따라서 더 엄격하게 적용하려면 [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시스템 및 로캘 에 따라 0123456789 이상과 일치할 수 있으므로 입력 유효성 검사에 사용해서는 안 됩니다(자세한 내용 [0-9][[:digit:]]이것은 다른 질문에 대한 답변입니다예를 들어).

또한bash패턴 일치는 멀티바이트 로케일에서 매우 놀라운 방식으로 작동합니다..

예를 들어 zh_CN.gb18030중국어 로케일 에서는 input='1-©©'예상대로 반환되지만 단일 바이트( ) no more than 4 digits but also contains non-digits를 추가하면 반환됩니다 .0x80input='1-©©'$'\x80'contains more than 4 digits

이러한 이유(그리고 많은 쉘의 코너 케이스에서 패턴 일치가 버그가 있다는 사실) 때문에 입력 유효성 검사를 위해 가능할 때마다 허용하는 것에 대해 (부정적 일치보다는) 긍정적인 일치(부정적 일치와 반대)를 사용하는 것이 더 좋습니다. ) 거부하려는 항목에 대해) 1 따라서 $d?($d)?($d)?($d)필수는 아니지만 적어도 이론적으로는 다른 항목이 이전 패턴과 일치해야 합니다.


1 예외적으로 Bourne 및 Korn 쉘의 단점을 고려할 수도 있습니다. 이 쉘 case $input in [x]) echo yes; esac은 !x[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

관련 정보