Compruebe si una matriz Bash contiene un valor
En Bash, ¿cuál es la forma más sencilla de probar si una matriz contiene un valor determinado?
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 IFS
los 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"
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
Solución de una línea
printf '%s\0' "${myarray[@]}" | grep -F -x -z -- 'myvalue'
Explicación
La printf
declaración imprime cada elemento de la matriz, delimitado por caracteres nulos.
La grep
declaració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 \0
en 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 -z
opción grep y la sustitución %s\n
como su primer argumento printf).
Uso
Para poner esto en una if ... then
declaración:
if printf '%s\0' "${myarray[@]}" | grep -Fxqz -- 'myvalue'; then
# ...
fi
Agregué una -q
bandera a la grep
expresión para que no imprima coincidencias; simplemente tratará la existencia de una coincidencia como "verdadera".
Actualización : Gracias, presto8, por señalar la --line-regexp
bandera. Gracias, Tino, por señalar el caso en el que pueden existir nuevas líneas dentro de los elementos de la matriz.
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