No bash, a expressão condicional com o teste unário -v myvariable
testa se a variável myvariable
foi definida. Observe que myvariable
não deve ser expandido prefixando-o com um dólar, portanto, não $myvariable
. Agora acho que para elementos de matriz a expressão condicional -v myarray[index]
também funciona bem, sem a sintaxe de expansão completa ${myarray[$index]}
. Tente isto:
myarray[2]=myvalue
for i in 1 2 3
do
[ -v myarray\[i] ] && echo element $i is set
done
(observe o escape \[
para evitar globbing, como alternativa ao uso de aspas)
dá a saída desejada:
element 2 is set
Pergunta Este comportamento é seguro para uso , também conhecido como este comportamento documentado?
Adendo Depois de ler a resposta https://unix.stackexchange.com/a/677920/376817 de Stéphane Chazelas, expandi meu exemplo:
myarray[1]=val myarray[2]=val myarray[3]=val myarray[4]=val myarray[5]=val myarray[6]="" myarray[2]=""
unset myarray[3] myarray[4] myarray[5]
touch myarray4 myarrayi
myarray4=val myarrayi=val
então
for i in {0..7}; do [ -v myarray\[i] ] && echo element $i is set; done
dá
element 1 is set
element 2 is set
element 6 is set
Sem citar ou escapar da expressão de índice [i]
:
for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done
dá
element 0 is set
element 1 is set
element 2 is set
element 3 is set
element 4 is set
element 5 is set
element 6 is set
element 7 is set
O mesmo com a variável myarrayi
unset :
unset myarrayi
for i in {0..7}; do [ -v myarray[i] ] && echo element $i is set; done
dá
%nothing%
E finalmente com a expansão do índice as $i
(ainda sem citar ou escapar do colchete):
for i in {0..7}; do [ -v myarray[$i] ] && echo element $i is set; done
dá
element 1 is set
element 2 is set
element 4 is set
Porque
ls -l myarray*
mostra
-rw-rw-r-- 1 me us 0 nov 17 15:37 myarray4
-rw-rw-r-- 1 me us 0 nov 17 15:37 myarrayi
Em
bash
, você pode fazer:ou
Para testar se o elemento array do índice 2 ou o elemento array associativo da chave "2" está definido (mesmo que seja uma string vazia), mas observe:
Ao usar o comando
[
(akatest
), você precisa citar os caracteres[
e]
como eles são operadores globbing. Como[
é apenas um comando comum, é interpretado como qualquer outro comando comum, então oa[2]
in[ -v a[2] ]
seria expandido da mesma maneira que inls -d a[2]
orunset a[2]
. Se houvesse um arquivo chamadoa2
no diretório de trabalho atual,a[2]
seria expandido para isso. E se não houvesse, mas onullglob
oufailglob
estivesse ativadoa[2]
, expandiria para nada ou daria um erro, respectivamente.[[ ... ]]
é uma construção especial com sua própria sintaxe, então não teria o problema.Para matrizes associativas (pelo menos na versão 5.1 em que testei), se a chave a ser verificada estiver em uma
$i
variável, você desejaria[ -v 'a[$i]' ]
ou[[ -v 'a[$i]' ]]
e aassoc_expand_once
opção introduzida em versões mais recentes debash
não ser ativada. Usandoou[ -v "a[$i]" ]
não funcionaria para alguns valores de[[ -v a[$i] ]]
$i
contenção]
ou barras invertidas. Aí, é o$
que deve ser citado. Veja também Como usar arrays associativos com segurança dentro de expressões aritméticas? .Ainda para arrays associativos, observe que
bash
(ao contrário doksh93
quebash
tentou copiar ouzsh
) não suporta as chaves vazias. Se você usar[[ -v 'a[$i]' ]]
e$i
for a string vazia, receberá um erro. Portanto, para testar valores de chave arbitrários, use[[ -n $i && -v 'a[$i]' ]]
ou[ -n "$i" ] && [ -v 'a[$i]' ]
.Para matrizes normais (esparsas), em
[ -v 'a[expr]' ]
ou[[ -v a[expr] ]]
,expr
é avaliado como uma expressão aritmética. É por isso que ambosi
e$i
funcionam. Como a expressão aritmética pode ter efeitos colaterais de atribuição de variáveis ou execução de comandos arbitrários, é importante que o valor de$i
usado[ -v 'a[i]' ]
seja sanitizado ou, caso contrário, você terá uma vulnerabilidade de execução de comandos arbitrários. Como visto em Implicações de segurança de esquecer de citar uma variável em shells bash/POSIX , o fatobash
de[ -v lvalue ]
funcionar para índices de matriz torna as coisas como[ -f $file ]
(onde o autor esqueceu de citar$file
) uma vulnerabilidade ACE.em qualquer caso, você sempre pode usar o método Bourne/POSIX (
[ -n "${var+set}" ]
) aplicado ao elemento array (associativo):[ -n "${a[$key]+set}" ]
que não precisa de nenhuma solução e funciona com todas as versões do bash com suporte a array (2.0 (1996) ou superior) ou suporte de matriz associativa (4.0 (2009) ou superior) e é portátil entre shells com eles.note que
[ -v var ]
na verdade é o mesmo que[ -v 'var[0]' ]
. Como no ksh88, as variáveis escalares podem ser vistas como o elemento do índice 0 de um array.para verificar se um array ou array associativo tem algum elemento (ou se uma variável escalar está configurada), você também pode fazer
[ "${#a[@]}" -gt 0 ]
ou[ -v 'a[@]' ]
ou[ -v 'a[*]' ]
.para percorrer os índices de matrizes esparsas ou chaves de matrizes associativas, você pode fazer:
(que dá
0
para uma variável escalar).Sobre se isso está documentado: se você executar
info bash test
ouinfo bash '['
, verá que ele adia as expressões condicionais do Bash (como usado dentro[[ ... ]]
de ), onde a documentação de-v
tem:Enquanto
help test
tem:O que
VARNAME
pode ser (em particular se os membros da matriz são permitidos) ou o que ele faz se seVARNAME
refere a uma variável que não é uma variável escalar não está claramente especificado. Mas, dado quea[x]
geralmente é permitido onde quer que um nome de variável seja esperado e que tem sido o caso há décadas, provavelmente podemos assumir com segurança que continuará sendo o caso no futuro.Se você observar outras seções dessa documentação oficial, verá que geralmente está implícito que sempre que um nome de variável é esperado (seja referido como NAME , VAR , VARNAME ou, mais geralmente , PARAMETER ),
varname[index]
também é aceito. Por exemplo, na documentação dounset
próprio (info bash unset
), não há menção aunset 'array[i]'
, mas é mencionado na seção sobre arrays .O
NEWS
arquivo na distribuição de origem (as notas de lançamento) nos diz quetest -v
foi adicionado no bash-4.2 (2011), provavelmente inspirado no ksh93, que o adicionou pouco antes no ksh93t + (2009, com suporte a elementos de matriz mencionado em suas próprias notas de lançamento)E em 4.3:
Em 5.1:
Você verá que
CWRU/changelog
na distribuição de origem há algumas menções detest -v array[@]
ou[[ -v array[$key] ]]
para matrizes associativas, sugerindo novamente o fato de que o recurso é intencional.Não é impossível que algumas coisas possam ser feitas no futuro para resolver alguns dos problemas mencionados acima, o que poderia invalidar as soluções alternativas que mencionei, como a necessidade de citar
$
.