正規表現を使用したケース文の数値の一致

正規表現を使用したケース文の数値の一致

シェルスクリプトへの引数が10進表記法で整数(例えば、負ではない整数: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

case正規表現を使用する代わりに、次を使用します。模様

「1つ以上の数字」の場合は、次の操作を行います。

shopt -s extglob
...
    case ${!i} in
        +([[:digit:]]) )
            n=${!i}
            ;;
    ...

正規表現を使用するには、=~次の演算子を使用してください。[[...]]

if [[ ${!i} =~ ^[[:digit:]]+$ ]]; then
    n=${!i}
else
    echo "Invalid"
fi

答え2

グレンが言ったように、"はcase正規表現を使用せず、次のように使用します。模様「。大きな打撃(1)説明する、

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

        caseコマンドが最初に展開されます。word、それぞれの項目と一致しようとします。pattern順番に、パス名拡張と同じ一致規則が使用されます(参照:パス名拡張次のような)。

同様に、POSIX仕様説明する、

…各模様...拡張と比較する必要があります。言葉, で説明されている規則に従ってパターンマッチング表記 …

だから模様ls -l -- *.shinまたはなどのパス名拡張パターン(別名ワイルドカード、別名ワイルドカード)rm -- *.bak

もちろん、shopt -s extglobスライス[[ … =~ … ]] したパンの後で最もきれいですが、POSIXではなく、元のツールの使い方を知っておくと便利です。たとえば、長年にわたり、プログラマは文字列が数字であるかどうかを調べて、数字かどうかを確認しました。いいえ数字。数字を(完全に)1つ以上の数字で構成される文字列として定義しました。したがって、文字列が空である場合、または数値以外の文字を含む場合、文字列は数値ではありません。case次の文を使用してこれらの条件をテストできます。

case "$1" in
    ("")
        # null
        ;;
    (*[!0-9]*)
        # contains non-numeric character(s)
        ;;
    (*)
        # is a whole number (non-negative integer)
esac

もちろん、数字を除くすべての文字を意味する古い[!0-9]シェル式はどこにありますか?[^0-9][!…]両方とも[^…]bashで動作します。  [!…]動作するにはPOSIXが必要で、結果は[^…]指定されていません。)文字列がどの種類の非数字であるかを問わない場合は、非数字モードを組み合わせることができます。

case "$1" in
    ("" | *[!0-9]*)
        # not a number
        ;;
    (*)
        # is a number
esac

練習として、ここにcaseすべての種類の間違い(正確には1つ以上の数字で構成される文字列、オプションでピリオド()、およびオプションでマイナス.記号())を処理するステートメントがあります。-

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

文字列に実際に少なくとも1つの数字が含まれていることを確認するためにcase-within-a-を追加しました。case文字列が空であることをテストしたので、整数の例ではこれは必要ありませんでした。このステートメントからテストを削除しました。 2番目がない場合は、case単一-または単一.(偶数-.)が数字と見なされます。もちろん、これらの例外を処理するためにパターンを追加できますが、これは複雑になる可能性があります。 (たとえば、私はこの回答が例外の-.1つであることに気付かずに公開することになっていました。)私は上記のアプローチがより柔軟で強力であると思います。

もちろん、数字以外のモードもここで組み合わせることができます (*[!-.0-9]* | *?-* | *.*.*)

答え3

到着case正規表現を使用した文の数値の一致、正規表現のワイルドカードサポートを持つシェルが必要です。私はこれでksh93だけを知っています。

ksh93 globを使用すると、globモードで拡張正規表現を実行または~(E)^[0-9]+$使用したり、~(E:^[0-9]+$)Perlに似た正規表現を使用したりできます(基本正規表現、高度正規表現、SysV正規表現でも機能します)。E~(P)^\d+$GXV

だから:

#! /bin/ksh93 -
for i do
  case $i in
    (~(E)^[0-9]+$)
      n=$i;;
    (*)
      echo >&2 'Invalid argument!'
      usage
  esac
done

関連情報