web-dev-qa-db-ja.com

if []からの "[:too many arguments"エラーの意味(角括弧)

次のBASH Shellエラーの意味を説明して修正するための単純明快なリソースが1つも見つからなかったので、調査の結果、投稿したものを投稿しました。

エラー:

-bash: [: too many arguments

Googleにやさしいバージョン:bash open square bracket colon too many arguments

Context:等号、等のような単純な比較演算子を含む単一の角括弧内のif条件。例えば、

VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
  # some action
fi 
165
user568458

$VARIABLEがスペースまたは他の特殊文字を含む文字列である場合、 および単一の大括弧が使用されます (これはtestコマンドのショートカットです)では、文字列は複数の単語に分割されます。これらはそれぞれ別々の引数として扱われます。

つまり、1つの変数が多くの引数に分割されます

VARIABLE=$(/some/command);  
# returns "hello world"

if [ $VARIABLE == 0 ]; then
  # fails as if you wrote:
  # if [ hello world == 0 ]
fi 

スペースや他の特殊文字を含む文字列を出力する関数呼び出しについても同じことが言えます。


簡単修正

変数の出力を二重引用符で囲み、1つの文字列(つまり1つの引数)のままにします。例えば、

VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
  # some action
fi 

そのように単純です。ただし、変数が空文字列にならないことも保証できない場合は、以下の「また注意してください」に進んでください。または空白文字しか含まない文字列。


あるいは、代替の修正は二重角括弧を使用することです(これはnew testコマンドのショートカットです)。

これはbash(そして明らかにkornとzsh)にのみ存在し、/bin/shなどによって呼ばれるデフォルトシェルと互換性がないかもしれません。これは例えば、コンソールからはうまくいくがcronからはうまくいかないかもしれませんすべての設定方法.

これは次のようになります。

VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
  # some action
fi 

[: unary operator expectedエラーにも注意してください

「引数が多すぎる」というエラーが表示される場合は、予測不可能な出力を含む関数から文字列を取得している可能性があります。 空の文字列(またはすべての空白文字列)を取得することも可能であれば、これは上記の "クイックフィックス"でもゼロ引数として扱われます。そして[: unary operator expectedで失敗します

他の言語に慣れていても、それは同じ「問題」です。評価される前に、変数の内容がこのようなコードに効果的に表示されることは期待できません。

これは[: too many arguments[: unary operator expectedの両方のエラーを防ぐ例です。出力が空の場合はデフォルト値(この例では0)で置き換え、全体を二重引用符で囲みます。

VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
  # some action
fi 

(ここでは、$ VARIABLEが0の場合、または空の場合にアクションが発生します。当然、異なる動作が必要な場合は、0(デフォルト値)を別のデフォルト値に変更する必要があります。


最後の注意:[testのショートカットなので、エラーtest: too many arguments(およびtest: unary operator expected)についても上記のすべてが当てはまります。

299
user568458

2つの変数がbothempty(またはnon-empty)であるかどうかをテストしようとすると、同じエラーが発生し、この記事に飛び込んできました。それは 複合比較 - 7.3であることが判明しました。その他の比較演算子 - 高度なBashスクリプトガイド ;そして私は次の点に注意すべきだと思いました:

  • 私が使った -e 最初は「空」という意味です。しかし、それは「ファイルが存在する」ことを意味します - 空の変数をテストするために-zを使用します(String)
  • 文字列変数は引用符で囲む必要があります
  • 複合論理AND比較の場合は、次のいずれかです。
    • 2つのtestsと&&をそれらを使ってください:[ ... ] && [ ... ]
    • または単一のtest-a演算子を使用します。[ ... -a ... ]

これが有効なコマンドです(ディレクトリ内のすべてのtxtファイルを検索し、grepが見つけたファイルをダンプするには、2つの単語が両方含まれています)。

find /usr/share/doc -name '*.txt' | while read file; do \
  a1=$(grep -H "description" $file); \
  a2=$(grep -H "changes" $file); \
  [ ! -z "$a1" -a ! -z "$a2"  ] && echo -e "$a1 \n $a2" ; \
done

2013年8月12日編集:関連問題メモ:

古典的なtest(一重角括弧[)で文字列の等価性をチェックするとき、あなたはMUSTの間にスペースが必要です。この場合、単数形の「等しい」=記号です(ただし、2つの等しい記号==も、等価演算子として受け入れられているようです)。したがって、これは(黙って)失敗します。

$ if [ "1"=="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] ; then echo A; else echo B; fi 
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi 
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi 
A

...しかし、スペースを追加してください - そして、すべてがよさそうです:

$ if [ "1" = "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi 
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi 
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi 
B
10
sdaau

誤ってキーボードに触れてスペースを空けた場合もあります。

if [ "$myvar" = "something"]; then
    do something
fi

このエラーメッセージが表示されます。 ']'の前のスペースが必要です。

2
Kemin Zhou

[: too many argumentsまたは[: a: binary operator expectedエラーが発生する可能性がある別のシナリオは、すべての引数"$@"をテストしようとした場合です。

if [ -z "$@" ]
then
    echo "Argument required."
fi

foo.shまたはfoo.sh arg1を呼び出すと、正常に機能します。ただし、foo.sh arg1 arg2のような複数の引数を渡すと、エラーが発生します。これは、有効な構文ではない[ -z arg1 arg2 ]に展開されているためです。

引数の存在を確認する正しい方法は、[ "$#" -eq 0 ]です。 ($#は引数の数です)。

1
wisbucky

私は自分のスクリプトで同じ問題を抱えています。しかし、私がいくつかの修正をしたとき、それは私のために働いた。私はこれが好きでした: -

export k=$(date "+%k");
if [ $k -ge 16 ] 
    then exit 0; 
else 
    echo "good job for nothing"; 
fi;

そのようにして私は自分の問題を解決した。それがあなたにも役立つことを願っています。

1
Kidane