Eu tenho uma matriz que é preenchida com diferentes mensagens de erro enquanto meu script é executado.
Eu preciso de uma maneira de verificar se está vazio ou não no final do script e executar uma ação específica, se estiver.
Eu já tentei tratá-lo como um VAR normal e usar -z para verificá-lo, mas isso não parece funcionar. Existe uma maneira de verificar se uma matriz está vazia ou não no Bash?
=
é um operador de cadeia. Por acaso funciona bem neste caso, mas eu usaria o operador aritmético adequado-eq
(apenas no caso de querer mudar para-ge
ou-lt
etc.).set -u
: "variável não acoplada" - se a matriz estiver vazia.set -u;
foo=();
[ ${#foo[@]} -eq 0 ] && echo empty
. Se euunset foo
, então ele imprimefoo: unbound variable
, mas isso é diferente: a variável da matriz não existe, ao invés de existir e estar vazia.set -u
- desde que você tenha declarado sua variável primeiro, isso funciona perfeitamente.Eu geralmente uso expansão aritmética neste caso:
fonte
(( ${#a} ))
(o comprimento do primeiro elemento) também funcionará. No entanto, isso falharáa=('')
, enquanto(( ${#a[@]} ))
que a resposta dada será bem-sucedida.Você também pode considerar a matriz como uma variável simples. Dessa forma, apenas usando
ou usando o outro lado
O problema com essa solução é que se uma matriz é declarada como este:
array=('' foo)
. Essas verificações reportarão a matriz como vazia, enquanto claramente não é. (obrigado @musiphil!)Usar
[ -z "$array[@]" ]
não é claramente uma solução também. Não especificar colchetes tenta interpretar$array
como uma sequência ([@]
nesse caso, é uma sequência literal simples) e, portanto, é sempre relatada como falsa: "a sequência literal está[@]
vazia?" Claramente não.fonte
[ -z "$array" ]
ou[ -n "$array" ]
não funciona. Tentearray=('' foo); [ -z "$array" ] && echo empty
e ele será impressoempty
mesmo quearray
claramente não esteja vazio.[[ -n "${array[*]}" ]]
interpola toda a matriz como uma sequência, que você verifica se há um comprimento diferente de zero. Se você consideraarray=("" "")
vazio, em vez de ter dois elementos vazios, isso pode ser útil.[[ -n " " ]]
é "true", o que é uma pena. Seu comentário é exatamente o que eu quero fazer.set -x
mostra como se expande. Acho que não testei esse comentário antes de postar. >. <Você pode fazê-lo funcionar definindoIFS=''
(salve / restaure em torno desta instrução), porque a"${array[*]}"
expansão separa elementos com o primeiro caractere do IFS. (Ou espaço, se não estiver definido). Mas " Se o IFS for nulo, os parâmetros serão unidos sem separadores intermediários " (documentos para parâmetros de posição $ *, mas eu assumo o mesmo para matrizes).Eu verifiquei com
bash-4.4.0
:e
bash-4.1.5
:No último caso, você precisa da seguinte construção:
para que não falhe na matriz vazia ou não configurada. Isso se você fizer
set -eu
como eu costumo fazer. Isso fornece uma verificação de erro mais rigorosa. Dos documentos :Se você não precisar disso, fique à vontade para omitir
:+${array[@]}
parte.Observe também que é essencial usar o
[[
operador aqui, para[
obter:fonte
-u
você deve realmente usar${array[@]+"${array[@]}"}
cf stackoverflow.com/a/34361807/1237617@
, certamente. Você poderia usar a*
expansão de array como[ "${array[*]}" ]
, não? Ainda assim,[[
também funciona bem. O comportamento de ambos para uma matriz com várias cadeias vazias é um pouco surpreendente. Ambos[ ${#array[*]} ]
e[[ "${array[@]}" ]]
são falsosarray=()
earray=('')
verdadeiros paraarray=('' '')
(duas ou mais cadeias vazias). Se você quiser que uma ou mais cadeias vazias sejam verdadeiras, use-a[ ${#array[@]} -gt 0 ]
. Se você quisesse que todos fossem falsos, talvez//
eles pudessem sair.[ "${array[*]}" ]
, mas se eu tivesse essa expressão, seria mais difícil para mim entender o que ela faz. Desde que[...]
opera em termos de seqüências de caracteres no resultado da interpolação. Ao contrário[[...]]
, que pode estar ciente do que foi interpolado. Ou seja, ele pode saber que foi passado um array.[[ ${array[@]} ]]
lê para mim como "verifique se a matriz não está vazia", enquanto[ "${array[*]}" ]
"verifique se o resultado da interpolação de todos os elementos da matriz é uma string não vazia".[ ${#array[*]} ]
, você provavelmente quis dizer[ "${array[*]}" ]
, já que o primeiro é válido para qualquer número de elementos. Porque o número de elementos é sempre uma sequência não vazia. Em relação ao último com dois elementos, a expressão entre colchetes se expande para a' '
qual é uma sequência não vazia. Quanto a[[ ${array[@]} ]]
eles, eles apenas pensam (e com razão) que qualquer matriz de dois elementos não esteja vazia.Se você deseja detectar uma matriz com elementos vazios , como
arr=("" "")
vazio, igual aarr=()
Você pode colar todos os elementos juntos e verificar se o resultado tem tamanho zero. (Construir uma cópia achatada do conteúdo da matriz não é ideal para desempenho, se a matriz puder ser muito grande. Mas espero que você não esteja usando o bash para programas como esse ...)
Mas se
"${arr[*]}"
expande com elementos separados pelo primeiro caractere deIFS
. Portanto, você precisa salvar / restaurar o IFS e fazerIFS=''
isso para funcionar, ou verifique se o comprimento da string == # dos elementos da matriz - 1. (Uma matriz den
elementos possuin-1
separadores). Para lidar com isso de um por um, é mais fácil diminuir a concatenação em 1caso de teste com
set -x
Infelizmente, este falhar por
arr=()
:[[ 1 -ne 0 ]]
. Portanto, você precisa verificar as matrizes realmente vazias primeiro separadamente.Ou com
IFS=''
. Provavelmente, você deseja salvar / restaurar o IFS em vez de usar um subshell, porque não é possível obter um resultado de um subshell facilmente.exemplo:
se trabalhar com
arr=()
- ainda é apenas uma string vazia.fonte
[[ "${arr[*]}" = *[![:space:]]* ]]
, pois posso contar com pelo menos um caractere não WS.arr=(" ")
.No meu caso, a segunda resposta não foi suficiente porque poderia haver espaços em branco. Eu vim junto com:
fonte
echo | wc
parece desnecessariamente ineficiente em comparação ao uso de shell embutidos.[ ${#errors[@]} -eq 0 ];
para solucionar o problema de espaço em branco? Eu também prefiro o embutido.$#
expande para um número e funciona bem mesmo depoisopts+=("")
. por exemplo,unset opts;
opts+=("");opts+=(" "); echo "${#opts[@]}"
e eu entendo2
. Você pode mostrar um exemplo de algo que não funciona?opts=("")
o mesmo queopts=()
? Essa não é uma matriz vazia, mas você pode verificar a matriz vazia ou o primeiro elemento vazio comopts=("");
[[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty
. Observe que sua resposta atual diz "sem opções" paraopts=("" "-foo")
, o que é totalmente falso, e isso reproduz esse comportamento. Você poderia[[ -z "${opts[*]}" ]]
adivinhar, para interpolar todos os elementos da matriz em uma sequência plana, que-z
verifica se há um comprimento diferente de zero. Se a verificação do primeiro elemento for suficiente,-z "$opts"
funciona.Eu prefiro usar colchetes duplos:
fonte