Làm thế nào để kiểm tra nếu các phần tử mảng đều bằng nhau trong bash?


15

Mảng sau đây đại diện cho số lượng đĩa trên mỗi máy linux

Mỗi mảng đơn bao gồm số lượng đĩa trên máy linux .

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

cách đơn giản để xác định rằng tất cả các giá trị của mảng là bằng nhau?

Tình trạng tốt:

4 4 4 4 4 4 4 4

Tình trạng xấu:

4 4 4 4 4 4 2 4

Tình trạng xấu:

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

Rất nhiều câu trả lời và không có phiếu bầu?
Jesse_b

Đây sẽ chỉ là kiểm tra số nguyên hay nó cũng nên kiểm tra chuỗi?
Jesse_b

Tôi chỉ chờ câu trả lời tốt nhất, đừng lo lắng, tôi sẽ bỏ phiếu
yael

Tôi có nghĩa là những người khác. Câu hỏi này xứng đáng nâng cấp IMO.
Jesse_b

một khi bạn cần một cái gì đó ít nhất là mức độ phức tạp này, đó là thời điểm tốt để bắt đầu sử dụng ngôn ngữ lập trình thực sự, cho đến khi quá muộn
Tên hiển thị

Câu trả lời:


11

bash+ Giải pháp sortGNU + 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

Giải thích bằng tiếng Anh: nếu phân loại duy nhất các phần tử của mảng chỉ dẫn đến một phần tử, sau đó in "ok". Nếu không thì in "xấu".

Mảng được in với NUL byte tách từng yếu tố, đường ống vào GNU loại (dựa trên -zaka --zero-terminated-uaka --uniquetùy chọn), và sau đó vào grep(sử dụng tùy chọn -zaka --null-data-caka --count) để đếm các dòng đầu ra.

Không giống như phiên bản trước của tôi, tôi không thể sử dụng wcở đây vì nó yêu cầu các dòng đầu vào được kết thúc bằng một dòng mới ... và sử dụng sedhoặc trđể chuyển đổi sortNUL thành dòng mới sau khi sẽ đánh bại mục đích sử dụng các dấu tách NUL. grep -clàm cho một sự thay thế hợp lý.


Đây là điều tương tự được viết lại như là một hàm:

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
Lưu ý rằng sort -ukhông trả về các phần tử duy nhất mà là một trong mỗi phần tử sắp xếp giống nhau. Chẳng hạn, nó sẽ nói "ok" ARRAY_DISK_Quantity=(① ②)trên một hệ thống GNU nơi các địa phương thường quyết định 2 ký tự đó sắp xếp giống nhau. Bạn muốn có LC_ALL=C sort -utính duy nhất từ ​​byte đến byte.
Stéphane Chazelas

chỉ cần một lưu ý khác là nó cũng sẽ thất bại trong trường hợp không có đĩa bổ sung nào xuất hiện từ CLI, do đó cũng cần thêm cú pháp này
yael

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

@ StéphaneChazelas vấn đề bản địa đáng để xử lý, cũng như vấn đề IFS. Kiểm tra danh sách trống là, IMO, được thực hiện riêng biệt tốt nhất - không cần kiểm tra các yếu tố không duy nhất trong một tập hợp trống.
cas

Xin chào Cas Tôi thích câu trả lời trước của bạn
yael

8

Với zsh:

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

Trường hợp (u)một cờ mở rộng tham số để mở rộng các giá trị duy nhất . Vì vậy, chúng tôi đang nhận được một số lượng các giá trị duy nhất trong mảng.

Thay thế == 1bằng <= 1là bạn muốn xem xét một mảng trống là OK.

Với ksh93, bạn có thể sắp xếp mảng và kiểm tra xem phần tử đầu tiên có giống với phần tử cuối cùng không:

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

Với ksh88 hoặc pdksh / mksh:

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

Với bash, bạn có thể cần một vòng lặp:

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

(sẽ hoạt động với tất cả các shell giống như Bourne với hỗ trợ mảng (ksh, zsh, bash, yash)).

Lưu ý rằng nó trả về OK cho một mảng trống. Thêm một [ "$#" -gt 0 ] || returnkhi bắt đầu chức năng nếu bạn không muốn điều đó.


Tất cả những câu trả lời dường như không hỗ trợ bash?
yael

@yael, xem chỉnh sửa cho một giải pháp bash. Nhưng tại sao bạn lại sử dụng bash?
Stéphane Chazelas

Trong Bash, trang trợ giúp cho typesetbiết Obsolete. See `help declare'.Có lý do gì bạn sử dụng nó thay vì localhay declarekhông?
wjandrea

1
@wjandrea typesetlà cái hoạt động trong cả 4 shell. Đây cũng là bản gốc từ ksh vào đầu những năm 80 (bash chủ yếu là sao chép ksh88 khi nói đến cài đặt và khai báo kiểu phạm vi thay đổi nhưng đã quyết định đổi tên typeset declarevà đặt typesetbí danh để khai báo).
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
}

Trường hợp thử nghiệm số 1:

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

Trường hợp thử nghiệm # 2:

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

4

Tôi có một giải pháp bash only khác cũng hoạt động với chuỗi:

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

Trình diễn:

[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

Lưu ý rằng các dấu chấm không hợp lệ trong tên hàm, mặc dù Bash khá dễ cho phép. Điều này có thể gây ra vấn đề như trong xuất khẩu chức năng.
wjandrea


2

Với bash và GNU grep:

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

Có, nhưng còn (10 10 10 10) thì sao? Nếu không, khá tốt đẹp.
Joe

@Joe: Bắt tốt. Tôi đã cập nhật câu trả lời của mình.
Cyrus

1

Đây là POSIX Awk:

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

0

bash chỉ giải pháp (giả sử aARRAY_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

Hoạt động, nhưng đếm tất cả các lỗi khi chỉ cần một lỗi là đủ:if [ "$ttt" -ne "$i" ]; then res=1; break; fi;
Joe

0

Sử dụng một vòng lặp for để so sánh từng phần tử mảng với phần tiếp theo. Kết thúc vòng lặp một vòng lặp nhỏ hơn độ dài của mảng để tránh so sánh phần tử cuối cùng với không có gì ở cuối.

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

Chào mừng bạn đến với U & L và cảm ơn sự đóng góp của bạn! Mã này sẽ in "Khớp" ngay cả khi tìm thấy sự không phù hợp ... có phải là dự định không?
fra-san
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.