Bashスクリプトに渡された引数の数を確認する


727

必要な引数の数が満たされていない場合、Bashスクリプトにエラーメッセージを出力させたいのですが。

私は次のコードを試しました:

#!/bin/bash
echo Script name: $0
echo $# arguments 
if [$# -ne 1]; 
    then echo "illegal number of parameters"
fi

不明な理由により、次のエラーが発生しました。

test: line 4: [2: command not found

何が悪いのですか?


54
スクリプトには名前を付けないでくださいtest。これは、標準のUnixコマンドの名前です。シャドウする必要はありません。
Barmar

20
bashでif文で'['( '[[')または'('( '((')の周りにスペースを必ず使用します。
zoska

5
@zoskaコメントに追加するには、[の前にスペースが必要です。コマンドとして実装されているため、 'which ['を試してください。
Daniel Da Cunha、

1
:より良い例は、リンクの下に記載してあり stackoverflow.com/questions/4341630/...
ラーマクリシュナ

3
@Barmar testは、PATH上にない限り、きっと名前を付けても大丈夫ですか?
user253751 2014年

回答:


1099

他の単純なコマンドと同じように、[ ... ]またはtest引数の間にスペースが必要です。

if [ "$#" -ne 1 ]; then
    echo "Illegal number of parameters"
fi

または

if test "$#" -ne 1; then
    echo "Illegal number of parameters"
fi

提案

Bashでは[[ ]]、変数の単語分割やパス名拡張を行わないため、代わりに使用することをお勧めします。式の一部でない限り、引用は必要ない場合があります。

[[ $# -ne 1 ]]

また、引用符で囲まれていない条件のグループ化、パターンマッチング(を使用した拡張パターンマッチングextglob)、正規表現マッチングなどの機能もあります。

次の例では、引数が有効かどうかを確認します。引数は1つまたは2つです。

[[ ($# -eq 1 || ($# -eq 2 && $2 == <glob pattern>)) && $1 =~ <regex pattern> ]]

純粋な算術式については、使用して(( ))いくつかのことはまだ良いかもしれないが、彼らはまだ可能であり、[[ ]]同様にその算術演算子と-eq-ne-lt-le-gt、または-ge単一の文字列引数として式を配置することによって:

A=1
[[ 'A + 1' -eq 2 ]] && echo true  ## Prints true.

[[ ]]同様に他の機能と組み合わせる必要がある場合に役立ちます。

スクリプトを終了する

無効なパラメーターがスクリプトに渡されたときにスクリプトを終了させることも論理的です。これは、すでに示唆されているコメントekangas誰かがして、それを持って、この答えを編集した-1私も右のそれを行う可能性がありますので、戻り値として。

-1ただし、Bashの引数として受け入れられていることexitは明示的に文書化されておらず、一般的な提案として使用することはできません。 64で定義されsysexits.h#define EX_USAGE 64 /* command line usage error */いるため、最も正式な値でもあります。のようなほとんどのツールは、無効な引数をls返し2ます。以前2はスクリプトで戻ることもありましたが、最近はあまり気にせず、単に1すべてのエラーで使用しました。ただし2、これは最も一般的で、おそらくOS固有ではないため、ここに配置します。

if [[ $# -ne 1 ]]; then
    echo "Illegal number of parameters"
    exit 2
fi

参考文献


2
OP:[別のコマンドであることを覚えておいてくださいwhich [。つまり、を試してください。
レオ

5
@Leoコマンドは組み込みにすることも、組み込むこともできません。bashでは、[は組み込み[[ですが、はキーワードです。一部の古いシェルで[は、組み込みではありません。のような[コマンドは、ほとんどのシステムで外部コマンドとして自然に共存しますが、commandまたはでバイパスしない限り、内部コマンドはシェルによって優先されますexec。評価方法については、シェルのドキュメントを確認してください。それらの違いと、どのシェルでそれらがどのように異なる動作をするかに注意してください。
konsolebox

78

数値を扱う場合は、算術式を使用することをお勧めします。

if (( $# != 1 )); then
    echo "Illegal number of parameters"
fi

今回のケースでは、なぜそれが良い考えでしょうか?効率、移植性、その他の問題を考慮すると、最も単純で最も一般的に理解されている構文を使用するのが最適ではありません[ ... ]か。
最大

@Max算術展開$(( ))は派手ではないため、すべてのPOSIXシェルで実装する必要があります。ただし、(( ))構文(なし$)はその一部ではありません。なんらかの理由で制限されている場合は、確かに[ ]代わりに使用できますが、使用しないでください[[ ]][ ]これらの機能が存在する理由とその理由を理解していただければ幸いです。しかし、これはBashの質問だったので、Bashの回答を提供します(「経験則として、[[は文字列とファイルに使用されます。数値を比較する場合は、ArithmeticExpressionを使用してください」)。
Aleks-Daniel Jakimenko-A。

40

[]:!=、=、== ...は文字列比較演算子、-eq、-gt ...は算術バイナリー演算子です。

私は使うだろう:

if [ "$#" != "1" ]; then

または:

if [ $# -eq 1 ]; then

9
==実際にはドキュメント化されていない機能で、たまたま GNUで動作しますtest。それはまた起こるのFreeBSDで動作するようにtest、しかし、ことでは動作しませfooという test唯一の標準的な比較である=(ちょうどFYI)。
Martin Tournoij 14

1
これはbash manエントリに文書化されています 。==および!=演算子が使用される場合、演算子の右側の文字列はパターンと見なされ、以下のパターンマッチングで説明されているルールに従ってマッチングされます。シェルオプションnocasematchが有効になっている場合、アルファベット文字の大文字と小文字に関係なく照合が実行されます。文字列がパターンに一致する(==)または一致しない(!=)場合、戻り値は0であり、それ以外の場合は1です。パターンの一部を引用符で囲んで、文字列として一致させることができます。
jhvaras 14年

2
@jhvaras:Carpetsmokerが言ったことまさにそのとおりです。一部の実装で機能する可能性があります(実際、Bashでも機能します)が、POSIX準拠ではありません。たとえば、次のように失敗dashますdash -c '[ 1 == 1 ]'。POSIXはのみを指定し=、指定はしません==
gniourf_gniourf 2017年

34

特定の引数が欠落している場合にのみベイル処理に関心がある場合は、パラメータ置換が最適です。

#!/bin/bash
# usage-message.sh

: ${1?"Usage: $0 ARGUMENT"}
#  Script exits here if command-line parameter absent,
#+ with following error message.
#    usage-message.sh: 1: Usage: usage-message.sh ARGUMENT

それはバシズムが満載ではないですか?
ドワイトスペンサー

@DwightSpencerそれは重要でしょうか?
konsolebox 2016年

@Temak特定の質問がある場合は私ができますが、リンク先の記事では、私よりもよく説明しています。
2016年

13

機能するシンプルなワンライナーは、以下を使用して実行できます。

[ "$#" -ne 1 ] && ( usage && exit 1 ) || main

これは次のように分類されます。

  1. パラメータのサイズについてbash変数をテストします$#が1と等しくない(サ​​ブコマンドの数)
  2. trueの場合、usage()関数を呼び出し、ステータス1で終了します
  3. それ以外の場合はmain()関数を呼び出す

注意すると思います:

  • usage()は単純なecho "$ 0:params"にすることができます
  • メインは1つの長いスクリプトにすることができます

1
その行の後に別の行のセットがある場合、それはexit 1サブシェルのコンテキストにのみ適用されるため、それはと同じ意味になり( usage; false )ます。私はオプションの解析に関してはそのような単純化のファンではありませんが、{ usage && exit 1; }代わりに使用できます。またはおそらく単に{ usage; exit 1; }
konsolebox 2016年

1
@konsolebox(usage && exit 1)は、bash 2.0に戻るksh、zsh、bashで機能します。{...}構文は、4.0以降のbashにのみ対応しています。ある方法がうまく機能してそれを使用しても、誤解しないでください。ただし、すべての人がbashの実装と同じ実装を使用しているわけではないので、bashismではなくposix標準にコーディングする必要があります。
ドワイトスペンサー

あなたの言っていることがよくわかりません。{...}は一般的な構文でありsh、POSIX標準に準拠していない古いシェルであっても、に基づくすべてのシェルではなくてもほとんどのシェルで使用できます。
konsolebox 2016年

7

この bashチートシートを確認してください。

渡された引数の長さを確認するには、次を使用します "$#"

渡された引数の配列を使用するには、次を使用します "$@"

長さのチェックと反復の例は次のようになります。

myFunc() {
  if [[ "$#" -gt 0 ]]; then
    for arg in "$@"; do
      echo $arg
    done
  fi
}

myFunc "$@"

この記事は私を助けましたが、私と私の状況のた​​めにいくつかのものが欠けていました。うまくいけば、これは誰かを助けます。


0

安全を確保したい場合は、getoptsを使用することをお勧めします。

ここに小さな例があります:

    while getopts "x:c" opt; do
      case $opt in
        c)
          echo "-$opt was triggered, deploy to ci account" >&2
          DEPLOY_CI_ACCT="true"
          ;;
            x)
              echo "-$opt was triggered, Parameter: $OPTARG" >&2 
              CMD_TO_EXEC=${OPTARG}
              ;;
            \?)
              echo "Invalid option: -$OPTARG" >&2 
              Usage
              exit 1
              ;;
            :)
              echo "Option -$OPTARG requires an argument." >&2 
              Usage
              exit 1
              ;;
          esac
        done

詳細については、ここhttp://wiki.bash-hackers.org/howto/getopts_tutorialを参照してください。


0

ここでは、1つのパラメーターのみが指定されているかどうかを確認する単純な1つのライナーを使用して、それ以外の場合はスクリプトを終了します。

[ "$#" -ne 1 ] && echo "USAGE $0 <PARAMETER>" && exit

-1

テスト条件の間にスペースを追加する必要があります:

if [ $# -ne 1 ]; 
    then echo "illegal number of parameters"
fi

これがお役に立てば幸いです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.