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

(すべてのロジックを中に入れることができますがcaseifそこに入れ子にするのは私の考えには少し見苦しいです。)


これは[[:digit:]]現在のロケールの「数値」の概念と一致する必要があります。これはASCII番号を超えることも、超えないこともあります0123456789。私のシステムでは、[[:digit:]]⁴(上付きの4、U + 2074)は一致しませんが、[0-9]一致します。他の「数字」を一致させることは問題になる可能性があります。シェルの数に対して算術演算を実行する場合。したがって、より厳密に適用するには、[0123456789]ASCII番号のみを許可を使用してください。

答え2

これは、ASCII 10進数のみを意味し、他のタイプの10進数または10進数以外の数字は意味しないと仮定します。

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

関連情報