6

bashについての質問...。

年がうるう年かどうかを確認するための小さなコードを作成しました。関連する部分は次のようになります。

if [ $testnum4 -eq 0 -a $testnum100 -ne 0 ] || [ $testnum400 -eq 0 ]
then
  echo 0
fi

まあ、このコードは実際に機能します。私の問題は、自分が何をしていたのかまだよくわからないことです。何が起こるかを見るために、私はこれについていくつかのバリエーションを試しました:正方形のバケツでテスト式全体を囲む、私が持っている場所と&&私が持っている場所を-a使用するなど。上記で書いた1つの式以外は何も機能しません。偶然見つけて良かったのですが、次回こんなことをしなければならない時は、自分が何をしているのか知りたいです。-o||

だから:誰もがbashで複合テストがどのように機能するかについて簡単に説明していますか?またはこのトピックに関する優れたリソースへのポインタ?

ありがとう。

失敗したコードは次のとおりです。

let testnum4=$1%4
let testnum100=$1%100
let testnum400=$1%400

if [ $testnum4 -eq 0 && $testnum100 -ne 0 ] -o [ $testnum400 -eq 0 ]
then
  echo 0
fi
4

4 に答える 4

18

ちょっとした注意: 角括弧は実際には Unix コマンドです。/bin/[システムにorというファイルがあるかどうか/usr/bin/[を確認します。実際、これを試してください:

$ ls i-il /bin[ /bin/test
571541 -r-xr-xr-x  2 root  wheel  43120 Aug 17  2011 /bin/[
571541 -r-xr-xr-x  2 root  wheel  43120 Aug 17  2011 /bin/test

最初の番号は i ノード番号です。あなたはそれを見て/bin/[/bin/testお互いに強く結びついています。それらは同じプログラムです。

この重要性については、後で説明します...


BASH およびその他の Bourne タイプのシェルでは、ifコマンドは単にコマンドを実行し、コマンドが終了コード を返す場合は、句0内のコマンドを実行します。ifコマンドが の終了コードを返さない場合、句0内のコマンドをスキップし、if句内のコマンドが存在する場合はそれを実行しますelse

したがって、これも有効です。

if sleep 2
then
   echo "That was a good nap!"
fi

お使いのコンピューターは、sleep 2(sleep コマンドが存在する場合) ゼロの終了コードを返し、エコーを続けるコマンドを実行します.

ifコマンドが実際に行うことはそれだけです。指定されたコマンドを実行し、終了コードを調べます。


さて、に戻り[ます...

testコマンドのマンページを参照してください。このコマンドには、if ステートメントtestと同じタイプのテストが多数含まれているように見えることがわかります。[...]実際、元の Bourne シェル (BASH の派生元) では、これらは同じコマンド構造です。

if test -f $my_file
then
    echo "File $my_file exists"
else
    echo "There is no file $my_file"
fi

if [ -f $my_file ]
then
    echo "File $my_file exists"
else
    echo "There is no file $my_file"
fi

実際、元の Bourne シェルでtestは、角括弧ではなくコマンドを使用する必要がありました。


では、元の質問に戻ります。-aおよび-oは、テスト コマンドのパラメーターです (マンページを参照してください。testたとえば、ifステートメントは次のように記述できます。

if test $testnum4 -eq 0 -a $testnum100 -ne 0 || test $testnum400 -eq 0
then
   echo 0
fi

ただし、&&||はテスト コマンドのパラメーターではないため、テスト コマンド内では使用できません。

これは BASH の組み込みコマンドであるため、BASH は元の Bourne シェルのように[実行されないことに注意してください。ただし、これはまだ存在しますが、BASH の組み込み/bin/[コマンドによく似たコマンドです。echo/bin/echo

于 2012-05-07T21:44:59.280 に答える
4

Bash で整数比較を行う正しい方法は、二重括弧を使用することです。

if (( (testnum4 == 0 && testnum100 != 0) || testnum400 == 0 ))
于 2012-05-07T19:44:23.277 に答える
1

アルゴリズム

うるう年をチェックするアルゴリズムは次のとおりです (疑似コード)。

if (YEAR modulo 400):
    LEAP_YEAR = true
elseif (YEAR modulo 4) and not (YEAR modulo 100):
    LEAP_YEAR = true
else
    LEAP_YEAR = false
endif

あまりにも巧妙なソリューションを使用しないことをお勧めします。より読みやすいものに固執します。ネストされた if ステートメントを使用したうるう年テストの実例については、 Bash 初心者向けガイドを参照してください。非推奨の$[]算術式を使用しているため、算術式を に置き換えるだけで、$(( ))どのように機能するかを確認できます。

OP コードの仕組み

OP の更新されたコード例では、値は位置パラメータから構築された個別の変数です。そのため、条件ステートメントで変数が評価される前に、モジュロ演算が変数に対して実行されます。その後、if ステートメントは次のように述べています。

if (first_expression returns true) or (second_expression returns true):
    echo 0
endif

一重角括弧は、コマンドと同じことを実行する単なるシェル組み込みでtestあり、式を評価し、ゼロが真である終了ステータスを返します。詳細についてはhelp \[、 またはman testを参照してください。

より良いネズミ捕りの構築

私と他の投稿者は、OP コードが機能する理由を説明しましたが、OP の目標の一部は、うるう年のテスト全体を 1 つの条件内に配置することであるようです。これを行う Bash シェル関数を次に示します。終了ステータスを調べて結果をテストできます。

# function returns exit status of arithmetic expression
leap_year () { 
    (( $1 % 400 == 0 || ($1 % 4 == 0 && $1 % 100 != 0) ))
}

プロンプトで関数をテストできます。

$ leap_year 2011; echo $?
1
$ leap_year 2012; echo $?
0
$ leap_year 2013; echo $?
1

(( ))算術式の詳細については、Bash リファレンス マニュアルの条件付き構成のセクションを参照してください。

于 2012-05-07T18:10:14.587 に答える
0

bash(実際にはほとんどのシェル)ifでは、コマンド/コマンドのセットを取り、then最後のコマンドがtrue(終了コードなし)を返す場合はセクションを評価し、そうでない場合はelif/elseセクションを評価します(elifelseと同様の方法で処理されます)。

について[[。これはtestコマンドに似ていますが、より広いテスト カバレッジを備えています。ただし、一度に 1 つの条件しか評価できないという制限があるため、-oまたは-aは受け入れません。の真の別名として見たいと思うかもしれません。およびこれらは、前のコマンドがそれぞれ false (ゼロ以外の終了コード) または true (ゼロの終了コード) を返す場合に次のコマンドを評価する制御演算子です。これら 2 つの使用は、コマンドを一緒にチェーンすることです (特に)。[test||&&[[

上記の if については、次の 2 つのコマンドを実行します。

  • 初め:[ $testnum4 -eq 0 -a $testnum100 -ne 0 ]
  • 2番:[ $testnum400 -eq 0 ]

最初のコマンドが成功した場合、if はthenセクションを実行します。最初のコマンドが失敗すると、2 番目のコマンドが実行されます。2 番目が成功した場合、本体が実行され、それ以外の場合は何もifしません。

優れた bash リソースについては、The Bash Wikiを参照してください。

于 2012-05-07T17:32:47.670 に答える