Bashスクリプトエラー[:!=:単項演算子が必要です


95

私のスクリプトでは、最初の唯一の引数が-vと等しいかどうかをエラーチェックしようとしていますが、これはオプションの引数です。ifステートメントを使用していますが、単項演算子の予期されるエラーが発生し続けます。

これはコードです:

if [ $1 != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

編集:

より具体的に説明する必要があります。上記のスクリプトのこの部分はオプションの引数をチェックし、その後、引数が入力されていない場合は、プログラムの残りの部分を実行する必要があります。

#!/bin/bash

if [ "$#" -gt "1" ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" != -v ]; then
   echo "usage: $0 [-v]"
   exit
fi

if [ "$1" = -v ]; then
   echo "`ps -ef | grep -v '\['`"
else
   echo "`ps -ef | grep '\[' | grep root`"
fi

...ところで、私はあなたが望むと思うecho "usage: $0 [-v]"; $-現在のスクリプトの名前ではなく、アクティブなシェルオプションフラグを表示します。
Charles Duffy、2014年

その部分は正しく、現在のスクリプトの名前を表示します。
user3380240 2014年

4
stackoverflowへ、特にbashタグへようこそ!このような多くの問題を指摘する(常に説明しているわけではありませんが)shellcheckなどの便利なツールとリソースについては、タグWikiをチェックしてください。
他の男、

@ user3380240 は、現在のスクリプトの名前で$-はありません$0です。
Charles Duffy

すみません、それはタイプミスでした。
user3380240 2014年

回答:


186

引用!

if [ "$1" != -v ]; then

それ以外の場合、$1が完全に空になると、テストは次のようになります。

[ != -v ]

の代わりに

[ "" != -v ]

...そして!=単項演算子(つまり、単一の引数のみを取ることができる演算子)ではありません。


8
あなたは、移植性を心配していない場合は、あなたは変数の展開が引用される必要がない内部を二重括弧を使用することができます if [[ $1 != -v ]]; then
マイク・ホルト

@MikeHolt、確かに-上記の質問に対するコメントでそれを取り上げます。
Charles Duffy

@DanielDinnyesは、ifの場合IFS=1[ $# -eq 1 ]それほどうまく動作しませんが、[ "$#" -eq 1 ]それでも意図したとおりに動作します。確かにそれは病的なケースですが、選択肢が与えられたときにそれを持たないソフトウェアを書く方が良いでしょう。
Charles Duffy

-2

あるいは、蔓延しているように見えるが実際には単純化されているものの場合...ほとんどすべてのケースをカバーし、空の文字列や単項の懸念はありません。

最初の引数が「-v」の場合は、条件付き ps -efで。それ以外の場合は、使用法をスローします。

#!/bin/sh
case $1 in
  '-v') if [ "$1" = -v ]; then
         echo "`ps -ef | grep -v '\['`"
        else
         echo "`ps -ef | grep '\[' | grep root`"
        fi;;
     *) echo "usage: $0 [-v]"
        exit 1;; #It is good practice to throw a code, hence allowing $? check
esac

'-v'引数の場所が気にならない場合は、単純にループ内でケースをドロップします。はすべての引数をたどり、どこにでも-vを見つけることができます(存在する場合)。つまり、コマンドライン引数の順序は重要ではありません。あらかじめ説明したように、変数arg_matchが設定されているため、これは単なるフラグです。'-v'引数を複数回使用できます。他のすべての '-v'の発生は簡単に無視できます。

#!/bin/sh

usage ()
 {
  echo "usage: $0 [-v]"
  exit 1
 }

unset arg_match

for arg in $*
 do
  case $arg in
    '-v') if [ "$arg" = -v ]; then
           echo "`ps -ef | grep -v '\['`"
          else
           echo "`ps -ef | grep '\[' | grep root`"
          fi
          arg_match=1;; # this is set, but could increment.
       *) ;;
  esac
done

if [ ! $arg_match ]
 then
  usage
fi

ただし、引数の複数の出現を許可すると、次のような場合に便利です。

$ adduser -u:sam -s -f -u:bob -trace -verbose

引数の順序は気にせず、複数の-u引数も許可します。はい、これも許可するのは簡単なことです:

$ adduser -u sam -s -f -u bob -trace -verbose

$*このコンテキストでは使用しないでください。アイテムを連結して、文字列分割とグローバル展開の両方を行う文字列にします。とは異なり"$@"、アイテムは正確な元の値のままになります。そして、shellcheck.netがキャッチするいくつかの引用符が欠落しています(これらの引用符が重要である理由を説明するWikiページにリンクされた警告が表示されます)。
Charles Duffy

、具体的な例として、考えてみましょう-U'Bob Barker'for arg in $*それが表示され-UBob、その後Barker、別の項目として、一方、単一の文字列としてfor item in "$@"表示さ-UBob Barkerれます。
Charles Duffy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.