¿Cómo probar si los elementos de la matriz son todos iguales en bash?


15

La siguiente matriz representa el número de discos en cada máquina Linux

Cada matriz individual incluye el número de discos en una máquina Linux .

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

¿Cuál es la manera simple de identificar que todos los valores de la matriz son iguales?

Buen estado:

4 4 4 4 4 4 4 4

Mal estado:

4 4 4 4 4 4 2 4

Mal estado:

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

¿Tantas respuestas y sin votos?
Jesse_b

¿Esto solo probará enteros o también probará cadenas?
Jesse_b

Solo estoy esperando la mejor respuesta, no te preocupes pronto votaré
yael

Me refería a todos los demás. Esta pregunta merece la votación de la OMI.
Jesse_b

una vez que necesite algo de al menos este nivel de complejidad, es un buen momento para comenzar a usar un lenguaje de programación real, hasta que sea demasiado tarde ...
Nombre para mostrar el

Respuestas:


11

bash+ GNU sort+ grepsolución 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

Explicación en inglés: si la clasificación única de los elementos de la matriz da como resultado un solo elemento, imprima "ok". De lo contrario, imprima "malo".

La matriz se imprime con bytes NUL que separan cada elemento, canalizados en GNU (confiando en -z opciones aka --zero-terminatedy -uaka --unique), y luego en grep(usando las opciones -zaka --null-datay -caka --count) para contar las líneas de salida.

A diferencia de mi versión anterior, no puedo usarlo wcaquí porque requiere líneas de entrada terminadas con una nueva línea ... y usando sedo trpara convertir NUL en nuevas líneas después de que sortse anule el propósito de usar separadores NUL. grep -chace un sustituto razonable.


Aquí está lo mismo reescrito como una función:

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
Tenga en cuenta que sort -uno devuelve elementos únicos, sino uno de cada conjunto de elementos que clasifican lo mismo. Por ejemplo, diría "ok" en ARRAY_DISK_Quantity=(① ②)un sistema GNU donde las configuraciones regionales generalmente deciden que esos 2 caracteres se ordenan de la misma manera. Lo que quiere LC_ALL=C sort -upara la unicidad byte a byte.
Stéphane Chazelas

sólo otra nota será fallan también en caso de que no son discos adicionales se desprende de la CLI así también la necesidad de añadir a esta sintaxis
Yael

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

@ StéphaneChazelas vale la pena abordar el problema de la configuración regional, al igual que el problema de IFS. La prueba de una lista vacía, IMO, se realiza mejor por separado: no hay necesidad de buscar elementos no únicos en un conjunto vacío.
cas

Hola Cas, prefiero tu respuesta anterior
yael

8

Con zsh :

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

Dónde (u) hay una bandera de expansión de parámetros para expandir valores únicos . Así que estamos obteniendo un recuento de los valores únicos en la matriz.

Reemplazar == 1 con <= 1si desea considerar que una matriz vacía está bien.

Con ksh93, puede ordenar la matriz y verificar que el primer elemento sea el mismo que el último:

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

Con ksh88 o pdksh / mksh:

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

Con bash, probablemente necesites un bucle:

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

(funcionaría con todos los shells tipo Bourne con soporte de matriz (ksh, zsh, bash, yash)).

Tenga en cuenta que devuelve OK para una matriz vacía. Agregue un [ "$#" -gt 0 ] || returnal comienzo de la función si no quiere eso.


todas estas respuestas no parecen apoyar bash?
yael

@yael, vea editar para una solución bash. ¿Pero por qué usarías bash?
Stéphane Chazelas

En Bash, la página de ayuda typesetdice Obsolete. See `help declare'.¿Hay alguna razón por la que lo estás usando en lugar de localo declare?
wjandrea

1
@wjandrea typesetes la que funciona en los 4 proyectiles. También es el original de ksh a principios de los años 80 (bash copió principalmente ksh88 cuando se trata de la configuración y declaración del tipo de alcance variable, pero decidió cambiar el nombre typeset declarey crear typesetun alias para declarar).
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
}

Caso de prueba n. ° 1:

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

Caso de prueba # 2:

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

4

Tengo otra solución de bash only que también debería funcionar con cadenas:

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

Demostració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

Tenga en cuenta que los puntos no son válidos en los nombres de funciones, aunque Bash es bastante permisivo. Esto puede causar problemas como al exportar la función.
wjandrea


2

Con bash y GNU grep:

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

Sí, pero ¿qué pasa con (10 10 10 10)? De lo contrario, bastante agradable.
Joe

@ Joe: Buena captura. He actualizado mi respuesta.
Cyrus

1

Aquí está POSIX Awk:

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

0

bash only solution (suponiendo que aes 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

Funciona, pero los recuentos de todos los errores cuando sólo uno es suficiente:if [ "$ttt" -ne "$i" ]; then res=1; break; fi;
Joe

0

Use un bucle for para comparar cada elemento de la matriz con el siguiente. Finalice el ciclo una iteración menor que la longitud de la matriz para evitar comparar el último elemento con nada al final.

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

Bienvenido a U&L y gracias por tu contribución. Este código imprimirá "Coincidencia" incluso si se encuentra una falta de coincidencia ... ¿está destinado?
fra-san
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.