Compruebe si una matriz Bash contiene un valor

Resuelto Paolo Tedesco asked hace 14 años • 0 respuestas

En Bash, ¿cuál es la forma más sencilla de probar si una matriz contiene un valor determinado?

Paolo Tedesco avatar Sep 10 '10 22:09 Paolo Tedesco
Aceptado

Este enfoque tiene la ventaja de no necesitar recorrer todos los elementos (al menos no explícitamente). Pero dado que array_to_string_internal()en array.c todavía recorre los elementos de la matriz y los concatena en una cadena, probablemente no sea más eficiente que las soluciones de bucle propuestas, pero es más legible.

if [[ " ${array[*]} " =~ [[:space:]]${value}[[:space:]] ]]; then
    # whatever you want to do when array contains value
fi

if [[ ! " ${array[*]} " =~ [[:space:]]${value}[[:space:]] ]]; then
    # whatever you want to do when array doesn't contain value
fi

Tenga en cuenta que en los casos en que el valor que está buscando sea una de las palabras en un elemento de matriz con espacios, dará falsos positivos. Por ejemplo

array=("Jack Brown")
value="Jack"

La expresión regular verá "Jack" como si estuviera en la matriz aunque no lo esté. Por lo tanto, tendrá que cambiar IFSlos caracteres separadores en su expresión regular si aún desea utilizar esta solución, como esta

IFS="|"
array=("Jack Brown${IFS}Jack Smith")
value="Jack"

if [[ "${IFS}${array[*]}${IFS}" =~ "${IFS}${value}${IFS}" ]]; then
    echo "true"
else
    echo "false"
fi

unset IFS # or set back to original IFS if previously set

Esto imprimirá "falso".

Obviamente, esto también se puede utilizar como declaración de prueba, lo que permite expresarla en una sola línea.

[[ " ${array[*]} " =~ " ${value} " ]] && echo "true" || echo "false"
Keegan avatar Mar 13 '2013 19:03 Keegan

A continuación se muestra una pequeña función para lograr esto. La cadena de búsqueda es el primer argumento y el resto son los elementos de la matriz:

set +e #otherwise the script will exit on error
containsElement () {
  local e match="$1"
  shift
  for e; do [[ "$e" == "$match" ]] && return 0; done
  return 1
}

Una ejecución de prueba de esa función podría verse así:

$ array=("something to search for" "a string" "test2000")
$ containsElement "a string" "${array[@]}"
$ echo $?
0
$ containsElement "blaha" "${array[@]}"echo $?
1
patrik avatar Dec 20 '2011 11:12 patrik

Solución de una línea

printf '%s\0' "${myarray[@]}" | grep -F -x -z -- 'myvalue'

Explicación

La printfdeclaración imprime cada elemento de la matriz, delimitado por caracteres nulos.

La grepdeclaración utiliza los siguientes indicadores para hacer coincidir un elemento que contiene exactamente la cadena proporcionada myvalue(ni más ni menos):

  • -z/ --null-data- Las líneas terminan con un byte cero en lugar de una nueva línea.
  • -F/ --fixed-strings- Interpretar PATRONES como cadenas fijas, no como expresiones regulares.
  • -x/ --line-regexp- Seleccione solo aquellas coincidencias que coincidan exactamente con toda la línea.
  • --- Marca el final de las opciones de la línea de comandos, lo que hace que Grep procese " myvalue" como un argumento que no es una opción incluso si comienza con un guión.

¿ Por qué utilizamos un byte nulo \0en lugar de una nueva línea \n? En realidad, su matriz puede contener nuevas líneas dentro de sus elementos. (Si sabe que no es así, no dude en eliminar la -zopción grep y la sustitución %s\ncomo su primer argumento printf).


Uso

Para poner esto en una if ... thendeclaración:

if printf '%s\0' "${myarray[@]}" | grep -Fxqz -- 'myvalue'; then
    # ...
fi

Agregué una -qbandera a la grepexpresión para que no imprima coincidencias; simplemente tratará la existencia de una coincidencia como "verdadera".

Actualización : Gracias, presto8, por señalar la --line-regexpbandera. Gracias, Tino, por señalar el caso en el que pueden existir nuevas líneas dentro de los elementos de la matriz.

JellicleCat avatar Nov 28 '2017 22:11 JellicleCat
for i in "${array[@]}"
do
    if [ "$i" -eq "$yourValue" ] ; then
        echo "Found"
    fi
done

Para cuerdas:

for i in "${array[@]}"
do
    if [ "$i" == "$yourValue" ] ; then
        echo "Found"
    fi
done
Scott avatar Sep 10 '2010 15:09 Scott