Como testar se os elementos da matriz são todos iguais no bash?

14

A seguinte matriz representou o número de discos em cada máquina linux

Cada matriz única inclui o número de discos em uma máquina linux .

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

qual é a maneira simples de identificar que todos os valores do array são iguais?

Bom estado:

4 4 4 4 4 4 4 4

Status incorreto:

4 4 4 4 4 4 2 4

Status incorreto:

6 6 6 6 6 6 6 6 6 6 2 6 2
    
por yael 25.12.2017 / 11:28

8 respostas

10

bash + GNU sort + GNU grep solução:

if [ "${#array[@]}" -gt 0 ] && [ $(printf "%s
function count_unique() {
  local LC_ALL=C

  if [ "$#" -eq 0 ] ; then 
    echo 0
  else
    echo "$(printf "%s
if [ "${#array[@]}" -gt 0 ] && [ $(printf "%s
function count_unique() {
  local LC_ALL=C

  if [ "$#" -eq 0 ] ; then 
    echo 0
  else
    echo "$(printf "%s%pre%0" "$@" |
              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
0" "${array[@]}" | LC_ALL=C sort -z -u | grep -z -c .) -eq 1 ] ; then echo ok else echo bad fi
0" "$@" | 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
0" "${array[@]}" | LC_ALL=C sort -z -u | grep -z -c .) -eq 1 ] ; then echo ok else echo bad fi

Explicação em inglês: se a classificação única dos elementos da matriz resultar em apenas um elemento, imprima "ok". Caso contrário, imprima "ruim".

A matriz é impressa com bytes NUL separando cada elemento, inseridos na classificação GNU (contando com as opções -z aka --zero-terminated e -u aka --unique ) e, em seguida, em grep (usando opções -z aka --null-data e -c aka --count ) para contar as linhas de saída.

Ao contrário da minha versão anterior, não posso usar wc aqui porque ela exige linhas de entrada terminadas com uma nova linha ... e usar sed ou tr para converter NULs em novas linhas depois que sort for derrotar o propósito de usar separadores NUL. grep -c faz um substituto razoável.

Aqui está a mesma coisa reescrita como uma função:

%pre%     
por 25.12.2017 / 12:17
8

com zsh :

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

Em que (u) é um sinalizador de expansão de parâmetro para expandir valores exclusivos . Então, estamos obtendo uma contagem dos valores únicos na matriz.

Substitua == 1 por <= 1 se você quiser considerar uma matriz vazia como OK.

Com ksh93 , você pode classificar a matriz e verificar se o primeiro elemento é igual ao anterior:

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

Com ksh88 ou pdksh / mksh:

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

Com bash , você provavelmente precisará de um 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

(trabalharia com todas as shells parecidas com Bourne com suporte à matriz (ksh, zsh, bash, yash)).

Observe que ele retorna OK para uma matriz vazia. Adicione um [ "$#" -gt 0 ] || return no início da função se você não quiser isso.

    
por 25.12.2017 / 12:50
4

bash + awk solução:

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
}

Caso de teste # 1:

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

Caso de teste # 2:

ARRAY_DISK_Quantity=(4 4 4 4 4 4 4 4)
get_status "${ARRAY_DISK_Quantity[@]}"
status: Ok
    
por 25.12.2017 / 11:45
4

Eu tenho outra solução apenas bash que deve funcionar com strings também:

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

Demonstração:

[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
    
por 25.12.2017 / 13:25
2

Com bash e GNU grep:

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

Aqui está o POSIX Awk:

awk 'BEGIN {while (++z < ARGC) if (ARGV[z] != ARGV[1]) exit 1}' "${ARRAY_DISK_Quantity[@]}"
    
por 25.12.2017 / 23:29
0

apenas a solução bash (assumindo que 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
    
por 25.12.2017 / 11:58
0

Use um loop for para comparar cada elemento da matriz com o seguinte. Encerre o loop uma iteração menor que o comprimento do array para evitar comparar o último elemento com nada no final.

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