How to test if array elements are all equal in bash?

bash + GNU sort + GNU grep solution:

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

English explanation: if unique-sorting the elements of the array results in only one element, then print "ok". Otherwise print "bad".

The array is printed with NUL bytes separating each element, piped into GNU sort (relying on the -z aka --zero-terminated and -u aka --unique options), and then into grep (using options -z aka --null-data and -c aka --count) to count the output lines.

Unlike my previous version, I can't use wc here because it requires input lines terminated with a newline...and using sed or tr to convert NULs to newlines after the sort would defeat the purpose of using NUL separators. grep -c makes a reasonable substitute.


Here's the same thing rewritten as a function:

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

With zsh:

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

Where (u) is a parameter expansion flag to expand unique values. So we're getting a count of the unique values in the array.

Replace == 1 with <= 1 is you want to consider an empty array is OK.

With ksh93, you could sort the array and check that the first element is the same as the last:

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

With ksh88 or pdksh/mksh:

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

With bash, you'd probably need a 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

(would work with all the Bourne-like shells with array support (ksh, zsh, bash, yash)).

Note that it returns OK for an empty array. Add a [ "$#" -gt 0 ] || return at the start of the function if you don't want that.


bash + awk soltion:

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