回答:
配列が$errors
であると仮定すると、要素の数がゼロかどうかを確認するだけです。
if [ ${#errors[@]} -eq 0 ]; then
echo "No errors, hooray"
else
echo "Oops, something went wrong..."
fi
set -u
「非バインド変数」では使用できません-配列が空の場合。
set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
。Iの場合、がunset foo
出力されますがfoo: unbound variable
、それは異なります。配列変数は、存在して空ではなく、まったく存在しません。
set -u
ています-最初に変数を宣言している限り、これは完全に機能します。
配列を単純な変数とみなすこともできます。そのように、ちょうど使用
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
と、文字列([@]
その場合は単純なリテラル文字列)として解釈しようとするため、常に「リテラル文字列は[@]
空ですか?」と報告されます。明らかにない。
[ -z "$array" ]
または[ -n "$array" ]
動作しません。試してみてください。明らかに空ではありませんarray=('' foo); [ -z "$array" ] && echo empty
が、印刷empty
されますarray
。
[[ -n "${array[*]}" ]]
配列全体を文字列として補間し、長さがゼロでないことを確認します。array=("" "")
空の要素を2つ持つのではなく、空であると考える場合、これは便利です。
[[ -n " " ]]
「true」であり、残念です。あなたのコメントはまさに私がやりたいことです。
set -x
ように、それがどのように拡大するかを示しています。投稿する前にそのコメントをテストしなかったと思います。>。< 展開するとIFSの最初の文字で要素が区切られるIFS=''
ため、設定(このステートメントの前後に保存/復元)することで機能させることができ"${array[*]}"
ます。(または未設定の場合はスペース)。しかし、「IFSがnullの場合、パラメーターはセパレーターを介さずに結合されます。」($ *位置パラメーターのドキュメント、配列についても同じと想定しています)。
私はそれをチェックしました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
私が通常するように行う場合です。これにより、より厳密なエラーチェックが提供されます。ドキュメントから:
-e
単一の単純なコマンド(単純なコマンドを参照)、リスト(リストを参照)、または複合コマンド(複合コマンドを参照)で構成されるパイプライン(パイプラインを参照)がゼロ以外のステータスを返す場合、すぐに終了します。失敗したコマンドがwhileまたはuntilキーワードの直後のコマンドリストの一部、ifステートメントのテストの一部、&&または||で実行されたコマンドの一部である場合、シェルは終了しません。最後の&&または||に続くコマンド、パイプライン内の最後のコマンド以外のコマンド、またはコマンドの戻りステータスが!で反転されている場合を除きます。-eが無視されている間にコマンドが失敗したためにサブシェル以外の複合コマンドがゼロ以外のステータスを返す場合、シェルは終了しません。ERRのトラップは、設定されている場合、シェルが終了する前に実行されます。
このオプションは、シェル環境と各サブシェル環境に個別に適用され(コマンド実行環境を参照)、サブシェル内のすべてのコマンドを実行する前にサブシェルを終了させる場合があります。
複合コマンドまたはシェル関数が-eが無視されるコンテキストで実行される場合、複合コマンドまたは関数本体内で実行されるコマンドは、-eが設定され、コマンドがaを返す場合でも、-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
@
、確かにです。の*
ような配列展開を使用[ "${array[*]}" ]
できますか?それでも、[[
正常に動作します。複数の空の文字列を持つ配列に対するこれらの両方の動作は、少し驚くべきものです。両方[ ${#array[*]} ]
と[[ "${array[@]}" ]]
のために偽であるarray=()
とarray=('')
のためではなく、真array=('' '')
(二つ以上の空の文字列)。1つ以上の空の文字列をすべてtrueにしたい場合は、を使用できます[ ${#array[@]} -gt 0 ]
。それらをすべて偽りにしたい場合は、//
それらを除外することができます。
[ "${array[*]}" ]
、そのような表現に遭遇した場合、それが何をするのか理解するのが難しくなります。[...]
補間の結果の文字列の観点から動作するため。とは対照的に[[...]]
、補間されたものを認識することができます。つまり、配列が渡されたことを知ることができます。[[ ${array[@]} ]]
「配列が空でないかどうかを確認する」と読み、「[ "${array[*]}" ]
すべての配列要素の補間の結果が空でない文字列であるかどうかを確認する」と読みます。
[ ${#array[*]} ]
は[ "${array[*]}" ]
、前者は任意の数の要素に当てはまるため、おそらくを意味します。要素の数は常に空でない文字列であるためです。2つの要素を持つ後者に関しては、括弧内の式は、に展開' '
非空の文字列です。については[[ ${array[@]} ]]
、2つの要素の配列は空ではないと考えています(そして当然のことです)。
空のように空の要素を持つ配列を検出したい場合はarr=("" "")
、arr=()
すべての要素を貼り付けて、結果の長さがゼロかどうかを確認できます。(配列の内容の平坦化されたコピーを構築することは、配列が非常に大きくなる可能性がある場合、パフォーマンスにとって理想的ではありません。
しかし"${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
んで作業arr=()
-それはまだちょうど空の文字列です。
[[ "${arr[*]}" = *[![:space:]]* ]]
、少なくとも1つの非WSキャラクターに頼ることができるので、を使い始めました。
arr=(" ")
。
私の場合、空白が存在する可能性があるため、2番目の回答では不十分でした。私は一緒に来ました:
if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
echo "No options"
else
echo "Options found"
fi
echo | wc
シェルのビルトインを使用した場合と比較して、不必要に効率が悪いようです。
[ ${#errors[@]} -eq 0 ];
、空白の問題を回避できますか?私も組み込みを好むだろう。
$#
は数に展開され、の後でも正常に動作しopts+=("")
ます。例えばunset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
、私は得る2
。動作しないものの例を示してもらえますか?
opts=("")
、同じように扱う必要がありopts=()
ますか?これは空の配列ではありませんが、を使用して空の配列または空の最初の要素を確認できますopts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
。あなたの現在の答えはのために「オプションなし」と言っていることに注意してくださいopts=("" "-foo")
。 すべての配列要素をゼロ以外の長さをチェックするフラットな文字列に補間する[[ -z "${opts[*]}" ]]
と推測でき-z
ます。 最初の要素をチェックするだけで十分な場合、-z "$opts"
動作します。
私は二重括弧を使用することを好みます:
if [[ !${array[@]} ]]
then
echo "Array is empty"
else
echo "Array is not empty"
fi
ダブルブラケット:https : //stackoverflow.com/questions/669452/is-preferable-over-in-bash
=
は文字列演算子であることに注意してください。この場合はたまたまうまく動作しますが、-eq
代わりに適切な算術演算子を使用します(-ge
またはに切り替えたい場合-lt
など)。