AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 677909
Accepted
db-inf
db-inf
Asked: 2021-11-18 03:01:55 +0800 CST2021-11-18 03:01:55 +0800 CST 2021-11-18 03:01:55 +0800 CST

Teste unário -v em um elemento de matriz

  • 772

No bash, a expressão condicional com o teste unário -v myvariabletesta se a variável myvariablefoi definida. Observe que myvariablenã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 myarrayiunset :

    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
bash array
  • 1 1 respostas
  • 402 Views

1 respostas

  • Voted
  1. Best Answer
    Stéphane Chazelas
    2021-11-18T04:14:14+08:002021-11-18T04:14:14+08:00

    Em bash, você pode fazer:

    [ -v 'a[2]' ]
    

    ou

    [[ -v a[2] ]]
    

    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 [(aka test), 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 o a[2]in [ -v a[2] ]seria expandido da mesma maneira que in ls -d a[2]or unset a[2]. Se houvesse um arquivo chamado a2no diretório de trabalho atual, a[2]seria expandido para isso. E se não houvesse, mas o nullglobou failglobestivesse ativado a[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 $ivariável, você desejaria [ -v 'a[$i]' ]ou [[ -v 'a[$i]' ]]e a assoc_expand_onceopção introduzida em versões mais recentes de bash não ser ativada. Usando [ -v "a[$i]" ]ou [[ -v a[$i] ]]não funcionaria para alguns valores de $icontençã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 do ksh93que bashtentou copiar ou zsh) não suporta as chaves vazias. Se você usar [[ -v 'a[$i]' ]]e $ifor 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 ambos ie $ifuncionam. 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 $iusado [ -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 fato bashde [ -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:

      for key in "${!a[@]}"; do
        printf 'The element of key "%s" is set\n' "$key"
      done
      

      (que dá 0para uma variável escalar).

    Sobre se isso está documentado: se você executar info bash testou info bash '[', verá que ele adia as expressões condicionais do Bash (como usado dentro [[ ... ]]de ), onde a documentação de -vtem:

    -v VARNAME
    Verdadeiro se a variável shell VARNAME estiver definida (foi atribuído um valor).

    Enquanto help testtem:

     -v VAR         True if the shell variable VAR is set.
    

    O que VARNAMEpode ser (em particular se os membros da matriz são permitidos) ou o que ele faz se se VARNAMErefere a uma variável que não é uma variável escalar não está claramente especificado. Mas, dado que a[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 do unsetpróprio ( info bash unset), não há menção a unset 'array[i]', mas é mencionado na seção sobre arrays .

    O NEWSarquivo na distribuição de origem (as notas de lançamento) nos diz que test -vfoi 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)

    f. test// tem um novo operador unário [de variável, que retorna sucesso se 'variável' tiver sido definida.[[-v

    E em 4.3:

    ll. O operador binário test/ [/ [[ -v variableagora entende as referências de matriz.

    Em 5.1:

    x. test -v Nagora pode testar se o parâmetro posicional N está definido ou não.

    Você verá que CWRU/changelogna distribuição de origem há algumas menções de test -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 $.

    • 11

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve