Bagaimana cara menguji apakah elemen array semuanya sama di bash?


15

Array berikut mewakili jumlah disk pada setiap mesin linux

Setiap array tunggal termasuk jumlah disk pada mesin linux .

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

apa cara sederhana untuk mengidentifikasi bahwa semua nilai array sama?

Status yang baik:

4 4 4 4 4 4 4 4

Status salah:

4 4 4 4 4 4 2 4

Status salah:

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

Begitu banyak jawaban dan tidak ada suara?
Jesse_b

Apakah ini hanya bilangan bulat pengujian atau haruskah itu juga menguji string?
Jesse_b

Saya hanya menunggu jawaban terbaik jangan khawatir segera saya akan memilih
yael

Maksud saya orang lain. Pertanyaan ini layak mendapatkan IMO.
Jesse_b

setelah Anda memerlukan sesuatu yang setidak-tidaknya tingkat kerumitan ini, ini adalah saat yang tepat untuk mulai menggunakan bahasa pemrograman yang nyata, sampai semuanya terlambat ...
Nama Tampilan

Jawaban:


11

bash+ GNU sort+ grepsolusi GNU :

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

Penjelasan bahasa Inggris: jika mengurutkan secara unik elemen-elemen dari array hanya menghasilkan satu elemen, lalu cetak "ok". Kalau tidak cetak "buruk".

Array dicetak dengan byte NUL yang memisahkan setiap elemen, disalurkan ke semacam GNU (mengandalkan opsi -zalias --zero-terminateddan -ualias --unique), dan kemudian ke grep(menggunakan opsi -zalias --null-datadan -calias --count) untuk menghitung garis output.

Tidak seperti versi saya sebelumnya, saya tidak dapat menggunakan di wcsini karena membutuhkan jalur input yang diakhiri dengan baris baru ... dan menggunakan sedatau truntuk mengkonversi NUL ke baris baru setelah sortakan mengalahkan tujuan menggunakan pemisah NUL. grep -cmembuat pengganti yang masuk akal.


Inilah hal yang sama ditulis ulang sebagai fungsi:

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
Perhatikan bahwa sort -utidak mengembalikan elemen unik tetapi salah satu dari setiap set elemen yang mengurutkannya sama. Sebagai contoh, ini akan mengatakan "ok" pada ARRAY_DISK_Quantity=(① ②)sistem GNU di mana lokal biasanya memutuskan 2 karakter semacam itu sama. Anda ingin LC_ALL=C sort -ukeunikan byte-ke-byte.
Stéphane Chazelas

hanya catatan lain itu akan gagal juga kalau-kalau tidak ada disk tambahan yang muncul dari CLI jadi perlu juga untuk menambahkan sintaks ini
yael

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

@ StéphaneChazelas masalah lokal layak ditangani, seperti masalah IFS. Pengujian untuk daftar kosong adalah, IMO, paling baik dilakukan secara terpisah - tidak perlu memeriksa elemen yang tidak unik di set kosong.
cas

Hai Cas. Saya lebih suka jawaban Anda sebelumnya
yael

8

Dengan zsh:

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

Di mana (u)bendera ekspansi parameter untuk memperluas nilai unik . Jadi kami mendapatkan hitungan nilai unik dalam array.

Ganti == 1dengan <= 1apakah Anda ingin menganggap array kosong adalah OK.

Dengan ksh93, Anda bisa mengurutkan array dan memeriksa apakah elemen pertama sama dengan yang terakhir:

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

Dengan ksh88 atau pdksh / mksh:

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

Dengan bash, Anda mungkin perlu loop:

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

(akan bekerja dengan semua shell Bourne-like dengan dukungan array (ksh, zsh, bash, yash)).

Perhatikan bahwa ia mengembalikan OK untuk array kosong. Tambahkan a [ "$#" -gt 0 ] || returndi awal fungsi jika Anda tidak menginginkannya.


semua jawaban ini tampaknya tidak mendukung bash?
yael

@el, lihat sunting untuk solusi bash. Tapi mengapa Anda menggunakannya bash?
Stéphane Chazelas

Di Bash, halaman bantuan untuk typesetmengatakan Obsolete. See `help declare'.Apakah ada alasan Anda menggunakannya, bukan localatau declare?
wjandrea

1
@wjandrea typesetadalah yang bekerja di semua 4 shell. Ini juga yang asli dari ksh di awal 80-an (kebanyakan bash disalin ksh88 ketika datang ke pengaturan jenis variabel dan deklarasi tetapi memutuskan untuk mengganti nama typeset declaredan membuat typesetalias untuk menyatakan).
Stéphane Chazelas

4

bash+ awksoltion:

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 case # 1:

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

Test case # 2:

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

4

Saya punya solusi bash only yang harus bekerja dengan string juga:

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

Demonstrasi:

[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

Perhatikan bahwa titik-titik tidak valid dalam nama fungsi, meskipun Bash cukup permisif. Ini dapat menyebabkan masalah seperti dalam mengekspor fungsi.
wjandrea


2

Dengan bash dan GNU grep:

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

Ya, tapi bagaimana dengan (10 10 10 10)? Kalau tidak, cukup bagus.
Joe

@ Jo: Bagus tangkap. Saya telah memperbarui jawaban saya.
Cyrus

1

Berikut adalah POSIX Awk:

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

0

solusi bash only (dengan asumsi aadalah 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

Berhasil, tetapi menghitung semua kesalahan saat hanya satu yang cukup:if [ "$ttt" -ne "$i" ]; then res=1; break; fi;
Joe

0

Gunakan for for untuk membandingkan setiap elemen array dengan yang berikutnya. Akhiri loop satu iterasi kurang dari panjang array untuk menghindari membandingkan elemen terakhir dengan apa pun di akhir.

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

Selamat datang di U&L dan terima kasih atas kontribusi Anda! Kode ini akan mencetak "Cocokkan" bahkan jika ditemukan ketidakcocokan ... apakah ini dimaksudkan?
fra-san
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.