Dizi öğelerinin hepsinin bash'de eşit olup olmadığı nasıl test edilir?


15

Aşağıdaki dizi, her linux makinesindeki disk sayısını temsil etti

Her bir dizi , bir linux makinedeki disk sayısını içerir .

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

tüm dizinin değerlerinin eşit olduğunu belirlemenin basit yolu nedir?

İyi durum:

4 4 4 4 4 4 4 4

Kötü durum:

4 4 4 4 4 4 2 4

Kötü durum:

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

Pek çok cevap ve oy yok mu?
jesse_b

Bu yalnızca tam sayıları mı test edecek yoksa dizeleri de mi test etmeli?
jesse_b

Sadece en iyi cevabı bekliyorum Yakında endişelenme oy vereceğim
yael

Herkes demek istedim. Bu soru IMO'yu hak ediyor.
jesse_b

en azından bu karmaşıklık düzeyine sahip bir şeye ihtiyacınız olduğunda, çok geç olana kadar gerçek bir programlama dili kullanmaya başlamak için iyi bir zaman…
Display Name

Yanıtlar:


11

bash+ GNU sort+ GNU grepçözümü:

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

Türkçe açıklama: dizinin öğelerini benzersiz olarak sıralamak yalnızca bir öğeyle sonuçlanıyorsa, "ok" yazdırın. Aksi takdirde "kötü" yazdırın.

Dizi, her öğeyi ayıran NUL baytları ile yazdırılır, GNU türüne ( -zaka --zero-terminatedve -uaka --uniqueseçeneklerine dayanarak ) ve sonra çıktı satırlarını saymak için grep( -zaka --null-datave -caka seçeneklerini kullanarak ) borulara yazdırılır --count.

Önceki sürümümün aksine, wcburada kullanamıyorum çünkü yeni satırla sonlandırılmış giriş satırları gerektiriyor ... ve NUL ayırıcılarını kullanma amacını bozacak şekilde NUL'ları yeni satırlara dönüştürmek için sedveya kullanma. makul bir ikame yapar.trsortgrep -c


İşte bir işlev olarak yeniden yazılan aynı şey:

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
Bunun sort -ubenzersiz öğeler döndürmediğini, ancak aynı sıralamadaki her öğe kümesinden birini döndürdüğünü unutmayın . Örneğin, ARRAY_DISK_Quantity=(① ②)yerel ayarların genellikle bu 2 karakterin aynı şekilde sıralanmasına karar verdiği bir GNU sistemlerinde "tamam" diyecektir . LC_ALL=C sort -uBayt-bayt benzersizliği istersiniz .
Stéphane Chazelas


[[`printf"% s \ n "" $ {ARRAY_DISK_Quantity [@]} "| wc -l `-eq` printf "% s \ n" "$ {ARRAY_DISK_Quantity [@]}" | grep -c "0" `]] && echo fail
yael

@ StéphaneChazelas, IFS sorunu gibi yerel sorunla da uğraşmaya değer. Boş bir listeyi test etmek, IMO, en iyi ayrı ayrı yapılır - boş bir kümedeki benzersiz olmayan öğeleri kontrol etmeye gerek yoktur.
cas

Merhaba Cas Önceki cevabınızı tercih ederim
yael

8

İle zsh:

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

Benzersiz değerleri (u)genişletmek için parametre genişletme bayrağı nerede . Böylece dizideki benzersiz değerlerin bir sayısını elde ediyoruz.

Değiştir == 1, <= 1boş bir dizinin iyi olduğunu düşünmek istediğinizdir.

İle ksh93diziyi sıralayabilir ve ilk öğenin son öğeyle aynı olup olmadığını kontrol edebilirsiniz:

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

Ksh88 veya pdksh / mksh ile:

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

İle bash, muhtemelen bir döngüye ihtiyacınız olacaktır:

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

(dizi destekli Bourne benzeri tüm kabuklarla çalışır (ksh, zsh, bash, yash)).

Boş bir dizi için Tamam döndürdüğünü unutmayın. [ "$#" -gt 0 ] || returnİstemiyorsanız, işlevin başına bir ekleyin .


tüm bu cevaplar bash'ı desteklemiyor gibi görünüyor?
yael

@yael, bash çözümü için düzenlemeye bakın. Ama neden kullanasın ki bash?
Stéphane Chazelas

Bash, yardım sayfasına typesetdiyor Obsolete. See `help declare'.sen yerine kullanıyorsun bir nedeni var mı localyoksa declare?
wjandrea

1
@wjandrea typeset4 merminin hepsinde çalışan kişidir . Ayrıca 80'lerin başında ksh'dan orijinal olanıdır (bash, değişken kapsam tipi ayarı ve bildirimi söz konusu olduğunda çoğunlukla ksh88'i kopyaladı, ancak beyan etmek için yeniden adlandırmaya typeset declareve typesetbir takma ad yapmaya karar verdi ).
Stéphane Chazelas

4

bash+ çözüm 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
}

Test örneği # 1:

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

Test örneği # 2:

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

4

Ben de dizeleri ile çalışması gereken başka bir bash sadece çözüm var:

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'
}

gösteri:

[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

Noktaların işlev adlarında geçerli olmadığını unutmayın, ancak Bash oldukça izin vericidir. Bu, işlevi dışa aktarma gibi sorunlara neden olabilir.
wjandrea


2

Bash ve GNU grep ile:

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

Evet, ama ne olacak (10 10 10 10)? Aksi takdirde, oldukça güzel.
Joe

@ Joe: İyi yakaladın. Cevabımı güncelledim.
Cyrus

1

İşte POSIX Awk:

awk 'BEGIN {while (++z < ARGC) if (ARGV[z] != ARGV[1]) exit 1}' "${ARRAY_DISK_Quantity[@]}"

0

Bash tek çözüm (varsayarak aedilir 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

Çalışır, ancak bir tanesi yeterli olduğunda tüm hataları sayar:if [ "$ttt" -ne "$i" ]; then res=1; break; fi;
Joe

0

Her dizi öğesini bir sonrakiyle karşılaştırmak için for döngüsü kullanın. Son öğenin sonunda hiçbir şeyle karşılaştırılmasını önlemek için döngü dizisinin uzunluğundan daha az bir yineleme sonlandırın.

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

U&L'ye hoş geldiniz ve katkınız için teşekkür ederiz! Bu kod bir eşleşmeme olsa bile "Eşleş" yazacaktır ... amaçlanıyor mu?
fra-san
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.