web-dev-qa-db-ja.com

シェル:ifでパラメーター付きの関数を使用する

以下のコードを実行しようとしていますが、ifステートメントで関数を使用しようとすると、-bash: [: too many argumentsエラー。なぜそれが起こっているのですか?

前もって感謝します!

notContainsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 1; done
  return 0
}

list=( "pears" "apples" "bananas" "oranges" )
blacklist=( "oranges" "apples" )
docheck=1

for fruit in "${list[@]}"
do
    if [ notContainsElement "$fruit" "${blacklist[@]}" -a $docheck = 1 ]
    then
        echo $fruit
    fi
done
8

if [ ... ]を使用する場合、実際には[ユーティリティを使用しています(testと同じですが、最後の引数が]である必要があります)。

[は、関数の実行を理解できません。文字列が必要です。幸い、ここでは[を使用する必要はありません(少なくとも関数については)。

if [ "$docheck" -eq 1 ] && notContainsElement "$fruit" "${blacklist[@]}"; then
  ...
fi

最初に整数もチェックしているので、$docheckが1でない場合に関数をまったく呼び出さないようにすることにも注意してください。

これが機能するのは、ifが任意のコマンドを受け取り、そのコマンドの終了ステータスから何をするかを決定するためです。ここでは、[ ... ]テストを関数の呼び出しと組み合わせて使用​​し、&&を中間に置いて、複合コマンドを作成します。 [ ... ]テストと関数の両方が終了ステータスとしてゼロを返し、成功を通知した場合、複合コマンドの終了ステータスはtrueになります。

スタイルノートとして、配列に要素notが含まれているかどうかではなく、要素doesが要素に含まれているかどうかをテストします。

if [ "$docheck" -eq 1 ] && ! contains "$fruit" "${blacklist[@]}"; then ...

do配列に要素(if ! notContainsElement ...)が含まれているかどうかをテストしたい場合、関数テストでネガティブになるとロジックが台無しになります。

14
Kusalananda

試す

if notContainsElement "$fruit" "${blacklist[@]}" && test "$docheck" = 1
then
  • -aオプションはシェルでもtestオプションでもありません

ここで2つの部分のテストがあります

notContainsElement "$fruit" "${blacklist[@]}"
test $docheck = 1 ## or [ $docheck = 1 ]

次にifを使用してリンクします

if cmd1 && cmd2

指摘されたように-aはテストオプションですが、他のテストオプションでのみ使用できるため、

if [ "$a" -lt "$b" -a "$a" -lt "$c" ]

それをテストする$aは両方より低い$bおよび$c、ただし、テストスコープ内で他のコマンドを使用することはできません。

3
Archemar

これは一部の人々が好まないかもしれない代替案です。ブラックリスト配列を文字列に変換し、フルーツが削除された文字列が同じかどうかを確認します。文字列にスペースを埋め込むように編集されました。アップル/パイナップル問題を指摘してくれたスコットに感謝します。

badlist=" ${blacklist[@]} "
for f in "${list[@]}"
do
    if [[ "${badlist/" $f "/}" == "$badlist" ]]
    then
        echo "$f"
    fi
done

これはもっと簡単だと思いますが、多くの人が好む&&ロジックが欠けています。

0
Wastrel