web-dev-qa-db-ja.com

bashスクリプトの引数をチェックするのはすべての数字の文字列です

Bash FAQ は言う

単純な「数字の文字列」を検証している場合は、グロブでそれを行うことができます:

# Bash
if [[ $foo = *[!0-9]* ]]; then
    echo "'$foo' has a non-digit somewhere in it"
else
    echo "'$foo' is strictly numeric"
fi

「いいね、それは素晴らしくてシンプルに見える」と思った。次に、最初のエコーの後に「exit 1」を追加し、$foo$1に変更したことを除いて、それをスクリプトに正確に貼り付けました。

if [[ $1 = *[!0-9]* ]]; then
    echo "'$1' has a non-digit somewhere in it"
    exit 1
else
    echo "'$1' is strictly numeric"
fi

次に、これを実行してみました

$ sh foo.sh bar
bar
foo.sh: 6: [[: not found
'bar' is strictly numeric

私はBashの文盲です、言うのは恥ずかしいので、ここで何が間違っているのかわかりません。 オンラインBashマニュアル でサポートされている印象を受けましたが、正規表現と照合するための演算子は=~ですが、それを変更しても違いはありません。そして、ここで問題があると思われる[[演算子は標準に見えますが、[[ ]][ ]の違いはわかりませんが、どちらも式のテストに相当します。私の知る限り。私はbashでDebianスクイーズを使用しています

$ bash --version
GNU bash, version 4.1.5(1)-release (i486-pc-linux-gnu)

Debianはバージョン4.1-3と言っています。

4
Faheem Mitha

Bashスクリプトの場合、なぜshを呼び出すのですか?ご使用のシステムでは、shがbashではなく、Bourne/POSIXファミリーの他のシェルであることは明らかです。実際、それは dash であり、メモリ消費量と速度を低く抑えるように設計された小さなシェルであり、ほとんどサポートされているのは [〜#〜] posix [〜#〜] 構造と構築-ユーティリティで。

_[[ … ]]_は、POSIXではなく、bashおよびzshによって選択されたBourne構文のksh拡張です。移植可能なスクリプトでは、テストに_[ … ]_を使用する必要があります。標準構成では、パターンマッチングはサポートされていません。標準的なイディオムは case構文 を使用することです:

_case $1 in                        # branch to the first pattern that $1 matches
  *[!0-9]*)                       # pattern = anything containing a non-digit
    echo not a number             # do this if the first pattern triggered
    ;;                            # end of this case branch
  *)                              # pattern = anything (else)
    echo successor of $(($1-1))   # do this if the second pattern triggered
    ;;                            # end of this case branch
esac                              # end of the case construct
_

引数がすべて数字かどうかをテストする関数は次のとおりです。

_is_all_digits () {
  case $1 in *[!0-9]*) false;; esac
}
_

Digression:最初に上のスニペットでタイプミスをしました:$(($0-1))と書きました。これにより、奇妙なエラーメッセージが表示されました。

_$ ash foo.sh 42
foo.sh: 4: arithmetic expression: expecting EOF: "foo.sh-1"
$ ash ./foo.sh 42
./foo.sh: 4: arithmetic expression: expecting primary: "./foo.sh-1"
$ ksh ./foo.sh 42
./foo.sh: line 3: foo.sh: invalid variable name
$ pdksh ./foo.sh 42
./foo.sh[4]: ./foo.sh-1: unexpected `.'
$ bash foo.sh 42         
foo.sh: line 3: foo.sh-1: syntax error: invalid arithmetic operator (error token is ".sh-1")
$ bash ./foo.sh 42
./foo.sh: line 3: ./foo.sh-1: syntax error: operand expected (error token is "./foo.sh-1")
$ zsh foo.sh 42
foo.sh:3: bad floating point constant
_

_$0_はスクリプトの名前であるため、評価される算術式は_foo.sh-1_または_./foo.sh-1_でした。シェル間のエラーメッセージの多様性を見ることができます。 ashのメッセージと_./_なしのbashのメッセージが最も明確であることに少し驚いた。他のどのシェルも問題が算術式にあるとは述べていない。 Ashとpdkshは、エラーを1行だけ報告しすぎるとドッキングポイントを取得します。

bash foo.sh barで実行してみてください。 bashスクリプトを作成する場合は、bashを使用する必要があります。上記で使用されている[[および]]は、BourneShellの派生物であるbashにのみ含まれています。 shはBourneShellを意味し、bashと同じではない場合があります。 debianはshにダッシュを使用していると思います。代わりに、bash固有の機能を必要としないポータブルなBourneシェルスクリプトを作成する方法を学びたい場合は、代わりにgrepを使用してスクリプトを書き直すことができます。

if echo "$foo" | grep '^[0-9][0-9]*$' >/dev/null 2>&1; then
    echo "'$1' has a non-digit somewhere in it"
    exit 1
else
    echo "'$1' is strictly numeric"
fi
3
penguin359

POSIXに準拠しているため、 expr を使用することをお勧めします。

if [ "$(expr "$1" : '^[0-9]\+$')" = "0" ]; then
    echo "'$1' has a non-digit somewhere in it"
    exit 1
else
     echo "'$1' is strictly numeric"
fi
0
php-coder