web-dev-qa-db-ja.com

Bashで配列が空かどうかを確認する

スクリプトを実行すると、さまざまなエラーメッセージが表示される配列があります。

スクリプトの最後ではなく空かどうかを確認し、空の場合は特定のアクションを実行する方法が必要です。

私はすでにそれを通常のVARのように扱い、それをチェックするために-zを使用しようとしましたが、それはうまくいかないようです。 Bashで配列が空かどうかを確認する方法はありますか?

123
Marcos Sander

あなたの配列が$errors、要素の数がゼロかどうかを確認してください。

if [ ${#errors[@]} -eq 0 ]; then
    echo "No errors, hooray"
else
    echo "Oops, something went wrong..."
fi
156
Michael Hampton

この場合、一般的に算術展開を使用します。

if (( ${#a[@]} )); then
    echo not empty
fi
19
x-yuri

配列を単純な変数と見なすこともできます。このようにして、

_if [ -z "$array" ]; then
    echo "Array empty"
else
    echo "Array non empty"
fi
_

または反対側を使用して

_if [ -n "$array" ]; then
    echo "Array non empty"
else
    echo "Array empty"
fi
_

このソリューションの問題は、配列が次のように宣言されている場合です:array=('' foo)。これらのチェックは配列が空であると報告しますが、明らかにそうではありません。 (@musiphilに感謝!)

_[ -z "$array[@]" ]_を使用することも明らかに解決策ではありません。中括弧を指定しないと、_$array_が文字列(_[@]_の場合、単純なリテラル文字列)として解釈されるため、常にfalseとして報告されます: "リテラル文字列_[@]_は空ですか? 」明らかにそうではありません。

9
wget

bash-4.4.0で確認しました:

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]} ]]; then
        echo not empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

およびbash-4.1.5

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]:+${array[@]}} ]]; then
        echo non-empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

後者の場合、次の構成が必要です。

${array[@]:+${array[@]}}

空または未設定の配列で失敗しないようにするため。それは、私が通常行うようにset -euを行う場合です。これにより、より厳密なエラーチェックが提供されます。 the docs から:

-e

単一の単純なコマンド(単純なコマンドを参照)、リスト(リストを参照)、または複合コマンド(複合コマンドを参照)で構成されるパイプライン(パイプラインを参照)がゼロ以外のステータスを返した場合、すぐに終了します。失敗したコマンドが、whileまたはuntilキーワードの直後のコマンドリストの一部、ifステートメントのテストの一部、&&または||で実行されたコマンドの一部である場合、シェルは終了しません。最後の&&または||に続くコマンド、パイプライン内の最後のコマンドを除くすべてのコマンド、またはコマンドの戻りステータスが! -eが無視されているときにコマンドが失敗したため、サブシェル以外の複合コマンドがゼロ以外のステータスを返した場合、シェルは終了しません。 ERRのトラップが設定されている場合は、シェルが終了する前に実行されます。

このオプションは、シェル環境と各サブシェル環境に別々に適用され(コマンド実行環境を参照)、サブシェル内のすべてのコマンドを実行する前にサブシェルが終了する可能性があります。

-eが無視されているコンテキストで複合コマンドまたはシェル関数が実行される場合、複合コマンドまたは関数本体内で実行されるコマンドは、-eが設定されていてコマンドが障害ステータス。 -eが無視されるコンテキストで実行中に複合コマンドまたはシェル関数が-eを設定した場合、その設定は複合コマンドまたは関数呼び出しを含むコマンドが完了するまで効果がありません。

-u

設定されていない変数や、特別なパラメーター ‘@’または ‘*’以外のパラメーターは、パラメーター展開を実行するときにエラーとして扱います。エラーメッセージが標準エラーに書き込まれ、非インタラクティブシェルが終了します。

それが必要ない場合は、:+${array[@]}の部分を省略してもかまいません。

また、ここで[[演算子を使用することが不可欠であることに注意してください。[では、次のようになります。

$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
    echo non-empty
else
    echo empty
fi

$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty
3
x-yuri

空のelementsの配列を検出する場合は、arr=("" "")を空として、 arr=()と同じ

すべての要素を貼り付けて、結果の長さがゼロかどうかを確認できます。 (配列のコンテンツのフラット化されたコピーを構築することは、配列が非常に大きくなる可能性がある場合、パフォーマンスにとって理想的ではありません。しかし、うまくいけば、そのようなプログラムにbashを使用していない...)

ただし、"${arr[*]}"は、IFSの最初の文字で区切られた要素で展開されます。したがって、IFSを保存/復元し、IFS=''を実行してこれを機能させるか、文字列の長さ==#配列要素の数-1を確認する必要があります(n要素の配列にはn-1セパレーター)。 1つずつオフに対処するには、連結に1を埋め込むのが最も簡単です。

arr=("" "")

## Assuming default non-empty IFS
## TODO: also check for ${#arr[@]} -eq 0
concat="${arr[*]} "      # n-1 separators + 1 space + array elements
[[ "${#concat}" -ne "${#arr[@]}" ]]  && echo not empty array || echo empty array

set -xのテストケース

### a non-empty element
$ arr=("" "x")
  + arr=("" "x")
$ concat="${arr[*]} ";  [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
  + concat=' x '
  + [[ 3 -ne 2 ]]
  + echo not empty array
not empty array

### 2 empty elements
$ arr=("" "")
  + arr=("" "")
$ concat="${arr[*]} ";  [[ "${#concat}" -ne "${#arr[@]}" ]] && echo not empty array || echo empty array
  + concat='  '
  + [[ 2 -ne 2 ]]
  + echo empty array
empty array

残念ながら、これはarr=()で失敗します:[[ 1 -ne 0 ]]したがって、最初に実際に空の配列を個別に確認する必要があります。


またはIFS=''を使用します。サブシェルから結果を簡単に取得できないため、サブシェルを使用する代わりにIFSを保存または復元する必要があります。

# inside a () subshell so we don't modify our own IFS
(IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)

例:

$ arr=("" "")
$ (IFS='' ; [[ -n "${arr[*]}" ]] && echo not empty array || echo empty array)
   + IFS=
   + [[ -n '' ]]
   + echo empty array
empty array

doesarr=()で動作します-それはまだ空の文字列です。

2
Peter Cordes

私は二重括弧を使うことを好みます:

if [[ !${array[@]} ]]
then
    echo "Array is empty"
else
    echo "Array is not empty"
fi

二重括弧: https://stackoverflow.com/questions/669452/is-preferable-over-in-bash

1
Nick Tsai

私の場合、空白がある可能性があるため、 2番目の回答 では不十分でした。私は一緒に来ました:

if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
  echo "No options"
else
  echo "Options found"
fi
0
Micha