配列要素がすべてbashで等しいかどうかをテストするにはどうすればよいですか?


15

次の配列は、各Linuxマシンのディスク数を表しています

単一アレイには、Linuxマシン上のディスクの数が含まれます。

echo ${ARRAY_DISK_Quantity[*]}
4 4 4 4 2 4 4 4

すべての配列の値が等しいことを識別する簡単な方法は何ですか?

良い状態:

4 4 4 4 4 4 4 4

悪い状態:

4 4 4 4 4 4 2 4

悪い状態:

6 6 6 6 6 6 6 6 6 6 2 6 2

たくさんの答えがあり、投票はありませんか?
Jesse_b

これは整数のみをテストしますか、それとも文字列もテストする必要がありますか?
Jesse_b

最高の答えを待っているだけで、すぐに投票します
yael

私は他のみんなを意味しました。この質問は賛成IMOに値する。
Jesse_b

あなたは複雑さの少なくともこのレベルのものが必要に一度、それは手遅れになるまで、それは...、実際のプログラミング言語を使用して開始するには良い時間です
表示名

回答:


11

bash+ GNU sort+ GNU grepソリューション:

if [ "${#array[@]}" -gt 0 ] && [ $(printf "%s\000" "${array[@]}" | 
       LC_ALL=C sort -z -u |
       grep -z -c .) -eq 1 ] ; then
  echo ok
else
  echo bad
fi

英語の説明:配列の要素を一意にソートした結果、要素が1つだけの場合は、「ok」と出力します。それ以外の場合は、「bad」を印刷します。

アレイがソートGNUにパイプ(に依存する、各要素を分離バイトNULで印刷されている-z別名--zero-terminated-u別名--uniqueオプション)、その後にgrepオプションを使用して(-z別名--null-data-c aka--count)出力行をカウントします。

私の以前のバージョンとは異なり、wc改行で終了する入力行を必要とするため、ここで使用することはできません...そして、NULセパレータを使用する目的を無効にした後、sedまたはtrを使用してNULを改行に変換しますsortgrep -c合理的な代替品になります。


これは関数として書き直された同じものです:

function count_unique() {
  local LC_ALL=C

  if [ "$#" -eq 0 ] ; then 
    echo 0
  else
    echo "$(printf "%s\000" "$@" |
              sort --zero-terminated --unique |
              grep --null-data --count .)"
  fi
}



ARRAY_DISK_Quantity=(4 4 4 4 2 4 4 4)

if [ "$(count_unique "${ARRAY_DISK_Quantity[@]}")" -eq 1 ] ; then
  echo "ok"
else
  echo "bad"
fi

1
sort -u一意の要素は返されませんが、同じ並べ替えを行う要素の各セットの1つが返されることに注意してください。たとえばARRAY_DISK_Quantity=(① ②)、ロケールが通常これら2文字を同じようにソートすることを決定するGNUシステムでは、「OK」と表示されます。あなたはしたいと思いLC_ALL=C sort -uバイトツーバイト一意性のために。
ステファンシャゼル

それは場合にも失敗することになるだけで、別のノートも、この構文を追加する必要があるので、追加のディスクがCLIから表示されません
ヤエル

[[`` printf "%s \ n" "$ {ARRAY_DISK_Quantity [@]}" | wc -l `-eq` printf "%s \ n" "$ {ARRAY_DISK_Quantity [@]}" | grep -c "0" `]] &&エコー失敗
yael

@StéphaneChazelasロケールの問題は、IFSの問題と同様に対処する価値があります。IMOでは、空のリストのテストは個別に行うのが最適です。空のセット内の一意でない要素をチェックする必要はありません。
cas

こんにちはキャス私はあなたの前の回答好む
ヤエル

8

zsh

if ((${#${(u)ARRAY_DISK_Quantity[@]}} == 1)); then
  echo OK
else
  echo not OK
fi

一意の(u)を展開するパラメーター展開フラグはどこにありますか。したがって、配列内の一意の値の数を取得しています。

置換は、空の配列がOK == 1<= 1あることを考慮したいですか。

を使用するksh93と、配列を並べ替えて、最初の要素が最後の要素と同じであることを確認できます。

set -s -- "${ARRAY_DISK_Quantity[@]}"
if [ "$1" = "${@: -1}" ]; then
  echo OK
else
  echo not OK
fi

ksh88またはpdksh / mkshの場合:

set -s -- "${ARRAY_DISK_Quantity[@]}"
if eval '[ "$1" = "${'"$#"'}" ]'; then
  echo OK
else
  echo not OK
fi

ではbash、おそらくループが必要になります。

unique_values() {
  typeset i
  for i do
    [ "$1" = "$i" ] || return 1
  done
  return 0
}
if unique_values "${ARRAY_DISK_Quantity[@]}"; then
  echo OK
else
  echo not OK
fi

(配列をサポートするすべてのBourneのようなシェル(ksh、zsh、bash、yash)で動作します)。

空の配列に対してOKを返すことに注意してください。[ "$#" -gt 0 ] || return必要ない場合は、関数の先頭にを追加します。


これらすべての答えはbashをサポートしていないようです?
ヤエル

@ yael、bashソリューションの編集を参照してください。しかし、なぜ使用しbashますか?
ステファンシャゼラス

BashのヘルプページにtypesetObsolete. See `help declare'.localまたはの代わりに使用する理由はありますかdeclare
wjandrea

1
@wjandrea typesetは、4つのシェルすべてで機能するものです。また、80年代前半のksh のオリジナルのものです(変数スコープ型の設定と宣言に関しては、bashはほとんどksh88をコピーしましたが、名前を変更typeset declaretypesetて宣言するエイリアスを作成することにしました)。
ステファンシャゼラス

4

bash+ awkソリューション:

function get_status() {
    arr=("$@")    # get the array passed as argument
    if awk 'v && $1!=v{ exit 1 }{ v=$1 }' <(printf "%d\n" "${arr[@]}"); then 
        echo "status: Ok"
    else 
        echo "status: Bad"
    fi
}

テストケース#1:

ARRAY_DISK_Quantity=(4 4 4 4 4 2 4 4)
get_status "${ARRAY_DISK_Quantity[@]}"
status: Bad

テストケース#2:

ARRAY_DISK_Quantity=(4 4 4 4 4 4 4 4)
get_status "${ARRAY_DISK_Quantity[@]}"
status: Ok

4

文字列でも動作する別のbash専用ソリューションがあります。

isarray.equal () {
    local placeholder="$1"
    local num=0
    while (( $# )); do
        if [[ "$1" != "$placeholder" ]]; then
            num=1
            echo 'Bad' && break
        fi
        shift
    done
    [[ "$num" -ne 1 ]] && echo 'Okay'
}

デモンストレーション:

[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(4 4 4 4 2 4 4 4)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Bad
[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(4 4 4 4 4 4 4 4)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Okay
[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(four four four four two four four four)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Bad
[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(four four four four four four four four)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Okay

関数名ではドットは無効ですが、Bashはかなり寛容です。これにより、関数のエクスポートなどで問題が発生する場合があります。
wjandrea


2

bashとGNU grepを使用:

if grep -qE '^([0-9]+)( \1)*$' <<< "${ARRAY_DISK_Quantity[@]}"; then 
  echo "okay"
else
  echo "not okay"
fi

はい、しかし(10 10 10 10)はどうですか?そうでなければ、かなりいい。
ジョー

@ジョー:良いキャッチ。回答を更新しました。
サイラス


0

bashの唯一の解決策(と仮定aされますARRAY_DISK_Quantity

ttt=${a[0]}
res=0
for i in "${a[@]}"
do 
    let res+=$(if [ "$ttt" -ne "$i" ]; then echo 1; else echo 0; fi);  
done
if [ "$res" -eq 0 ]
then 
    echo "ok"
else
    echo "bad"
fi

動作しますが、一つだけが十分あるときにすべてのエラーをカウントします:if [ "$ttt" -ne "$i" ]; then res=1; break; fi;
ジョー

0

forループを使用して、各配列要素を次のものと比較します。配列の長さよりも1回少ないループを終了して、最後の要素と最後の要素を比較しないようにします。

for (( i=0; i<((${#array[@]}-1)); i++ )); do
    [ "${array[$i]}" != "${array[(($i+1))]}" ] && echo "Mismatch"
done
echo "Match"

U&Lにようこそ。ご協力ありがとうございます。このコードは、不一致が見つかった場合でも「Match」を出力します...これは意図したものですか?
fra-san
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.