Tengo una matriz que se llena con diferentes mensajes de error a medida que se ejecuta mi script.
Necesito una forma de verificar si está vacío o no al final del script y tomar una acción específica si es así.
Ya he intentado tratarlo como un VAR normal y usar -z para verificarlo, pero eso no parece funcionar. ¿Hay alguna manera de verificar si una matriz está vacía o no en Bash?
=
es un operador de cadena. En este caso, funciona bien, pero en su lugar usaría el operador aritmético adecuado-eq
(en caso de que quisiera cambiar a-ge
o-lt
, etc.).set -u
: "variable independiente" - si la matriz está vacía.set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
. Si lo hagounset foo
, se imprimefoo: unbound variable
, pero eso es diferente: la variable de matriz no existe en absoluto, en lugar de existir y estar vacía.set -u
, siempre que haya declarado su variable primero, esto funciona perfectamente.Generalmente uso la expansión aritmética en este caso:
fuente
(( ${#a} ))
(la longitud del primer elemento) también funcionará. Sin embargo, eso fallaráa=('')
, mientras que(( ${#a[@]} ))
dado en la respuesta tendrá éxito.También puede considerar la matriz como una variable simple. De esa manera, solo usando
o usando el otro lado
El problema con esta solución es que si se declara una matriz de esta manera:
array=('' foo)
. Estas comprobaciones informarán que la matriz está vacía, mientras que claramente no lo está. (¡Gracias @musiphil!)Usando
[ -z "$array[@]" ]
claramente no es una solución ni. Al no especificar llaves se intenta interpretar$array
como una cadena ([@]
en ese caso, es una cadena literal simple) y, por lo tanto, siempre se informa como falsa: "¿está[@]
vacía la cadena literal ?" Claramente no.fuente
[ -z "$array" ]
o[ -n "$array" ]
no funciona Intentearray=('' foo); [ -z "$array" ] && echo empty
, e imprimiráempty
aunquearray
claramente no esté vacío.[[ -n "${array[*]}" ]]
interpola toda la matriz como una cadena, que verifica para una longitud distinta de cero. Si consideraarray=("" "")
que está vacío, en lugar de tener dos elementos vacíos, esto podría ser útil.[[ -n " " ]]
es "verdadero", lo cual es una pena. Tu comentario es exactamente lo que quiero hacer.set -x
muestra cómo se expande. Supongo que no probé ese comentario antes de publicar. >. <Puede hacer que funcione estableciendoIFS=''
(guardar / restaurar alrededor de esta instrucción), porque la"${array[*]}"
expansión separa los elementos con el primer carácter de IFS. (O espacio si no está configurado). Pero " Si IFS es nulo, los parámetros se unen sin separadores intermedios " (documentos para $ * parámetros posicionales, pero supongo lo mismo para las matrices).Lo comprobé con
bash-4.4.0
:y
bash-4.1.5
:En el último caso, necesita la siguiente construcción:
para que no falle en una matriz vacía o desarmada. Eso si haces lo
set -eu
que yo suelo hacer. Esto proporciona una comprobación de errores más estricta. De los documentos :Si no necesita eso, no dude en omitir
:+${array[@]}
parte.También tenga en cuenta que es esencial usar el
[[
operador aquí, con lo[
que obtiene:fuente
-u
usted debería usar${array[@]+"${array[@]}"}
cf stackoverflow.com/a/34361807/1237617@
, seguramente. Podrías usar la*
expansión de matriz como[ "${array[*]}" ]
, ¿no? Aún así,[[
también funciona bien. El comportamiento de ambos para una matriz con múltiples cadenas vacías es un poco sorprendente. Ambos[ ${#array[*]} ]
y[[ "${array[@]}" ]]
son falsos paraarray=()
yarray=('')
pero verdaderos paraarray=('' '')
(dos o más cadenas vacías). Si quisieras que una o más cadenas vacías fueran verdaderas, puedes usarlas[ ${#array[@]} -gt 0 ]
. Si quisieras que todos fueran falsos, podrías//
eliminarlos.[ "${array[*]}" ]
, pero si tuviera esa expresión, me sería más difícil entender lo que hace. Dado que[...]
opera en términos de cadenas en el resultado de la interpolación. A diferencia de[[...]]
, que puede ser consciente de lo que se interpola. Es decir, puede saber que se le pasó una matriz.[[ ${array[@]} ]]
me dice como "verificar si la matriz no está vacía", mientras que[ "${array[*]}" ]
como "verificar si el resultado de la interpolación de todos los elementos de la matriz es una cadena no vacía".[ ${#array[*]} ]
, probablemente quiso decir[ "${array[*]}" ]
, ya que lo primero es cierto para cualquier número de elementos. Porque el número de elementos siempre es una cadena no vacía. Con respecto a este último con dos elementos, la expresión entre paréntesis se expande a la' '
cual es una cadena no vacía. En cuanto a[[ ${array[@]} ]]
, simplemente piensan (y con razón) que cualquier conjunto de dos elementos no está vacío.Si desea detectar una matriz con elementos vacíos ,
arr=("" "")
como vacío, igual quearr=()
Puede pegar todos los elementos juntos y verificar si el resultado es de longitud cero. (Construir una copia aplanada del contenido de la matriz no es ideal para el rendimiento si la matriz puede ser muy grande. Pero espero que no estés usando bash para programas como ese ...)
Pero se
"${arr[*]}"
expande con elementos separados por el primer carácter deIFS
. Por lo tanto, debe guardar / restaurar IFS y hacerIFS=''
que esto funcione, o bien comprobar que la longitud de la cadena == # de elementos de la matriz - 1. (Una matriz den
elementos tienen-1
separadores). Para lidiar con eso fuera de uno, es más fácil rellenar la concatenación en 1caso de prueba con
set -x
Por desgracia, esta falla por
arr=()
:[[ 1 -ne 0 ]]
. Por lo tanto, primero deberá verificar las matrices realmente vacías por separado.O con
IFS=''
. Probablemente quiera guardar / restaurar IFS en lugar de usar una subshell, porque no puede obtener un resultado de una subshell fácilmente.ejemplo:
no funciona con
arr=()
- sigue siendo sólo la cadena vacía.fuente
[[ "${arr[*]}" = *[![:space:]]* ]]
, ya que puedo contar con al menos un personaje que no sea WS.arr=(" ")
.En mi caso, la segunda respuesta no fue suficiente porque podría haber espacios en blanco. Llegué junto con:
fuente
echo | wc
parece innecesariamente ineficiente en comparación con el uso de shell incorporado.[ ${#errors[@]} -eq 0 ];
para evitar el problema del espacio en blanco? También preferiría el incorporado.$#
se expande a un número y funciona bien incluso despuésopts+=("")
. Por ejemplo,unset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
y lo consigo2
. ¿Puedes mostrar un ejemplo de algo que no funciona?opts=("")
lo mismo queopts=()
? Esa no es una matriz vacía, pero puede verificar si hay una matriz vacía o un primer elemento vacío conopts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
. Tenga en cuenta que su respuesta actual dice "no hay opciones" paraopts=("" "-foo")
, que es totalmente falso, y esto reproduce ese comportamiento. Podría[[ -z "${opts[*]}" ]]
adivinar, para interpolar todos los elementos de la matriz en una cadena plana, que-z
verifica la longitud no cero. Si verificar el primer elemento es suficiente,-z "$opts"
funciona.Prefiero usar corchetes dobles:
fuente