Possível bug no Bash ?: foo () {echo “$ {var [0]}”; }; var = (barra baz) foo

22

Sistema operacional : Ubuntu 16.04.3

Shell : Bash 4.3.48


Eu sei que é possível alterar temporariamente o conteúdo de uma variável como em var=value command, sendo provavelmente IFS= read -r varo caso mais notável disso.

E, graças ao wiki de Greg , eu também entendo:

# Why this
foo() { echo "$var"; }
var=value foo

# And this does work
var=value; echo "$var"

# But this doesn't
var=value echo "$var"

O que escapa ao meu entendimento é o seguinte:

$ foo() { echo "${var[0]}"; }
$ var=(bar baz) foo
(bar baz)

Tanto quanto eu sei (e seguindo a lógica dos exemplos anteriores), ele deve imprimir bar, não (bar baz).

Isso só acontece comigo? Esse é o comportamento pretendido e estou perdendo alguma coisa? Ou isso é um bug?

nxnev
fonte
3
Talvez tenha algo a ver com o fato de que o bash não suporta matrizes como variáveis ​​ambientais?
Jesse_b
3
@Jesse_b Talvez. Embora, quando eu corro export var=(foo bar); echo "${var[0]}", imprima foo, não (foo bar).
Nxnev
1
Estranho, isso funcionou para mim também. E usá- exportlo mostra:declare -ax var=([0]="foo" [1]="bar")
Jesse_b
3
O ambiente não pode conter matrizes, AFAIK. Por exemplo, export i_am_array=(foo bar); /usr/bin/env | grep i_am_arraynão dá saída aqui.
derobert
3
Também: foo() { declare -p var; } ; var=(bar baz) foodeclare -x var="(bar baz)"confirmando que está sendo tratado como uma string, não uma matriz
derobert

Respostas:

19

Geralmente chamando:

var=value cmd

onde cmdé uma função não é portátil.

Com bash, que funciona apenas para variáveis ​​escalares (e com x=(...)analisado como uma matriz, mas atribuído como escalar) e há vários problemas com o escopo, se você fizer isso, com ksh93e yash, ele funciona, mas a definição de variável permanece posteriormente. Com mksh, você recebe um erro de sintaxe. No shell Bourne, não funcionou, mesmo para variáveis ​​escalares.

Observe também que, mesmo com variáveis ​​escalares, se a variável acaba sendo exportada dentro da função (ou seja, passada para comandos sendo executados) varia de shell para shell (está no bash, yash, mksh, zsh, mas não no ksh, cinza).

Só funciona da maneira que você esperaria zsh. Observe que os zshíndices da matriz começam em 1.

bash-4.4$ zsh
$ a=(before value)
$ f() echo $a[1]
$ a=(temp value) f
temp
$ echo $a[1]
before
Stéphane Chazelas
fonte
12

Não é apenas um bug, parece ser um recurso não implementado, sem planos de ser. Esta postagem na lista de discussão de 2014 tem isso do criador:

Felizmente, no bash 4.3 (nível 25 de patch), você não pode simplesmente -DARRAY_EXPORT e obter a importação / exportação da variável de matriz. O código não é compilado e, se você corrigir isso, ele não vincula, e se você corrigir isso, bem, você acaba com o seguinte problema.

Isso é uma tonelada de problemas para passar apenas por isso. Não tenho planos para ativar a exportação de matriz.

A partir do mais recente repositório git para Bash, temos isso em variables.c:

  #  if ARRAY_EXPORT
        /* Array variables may not yet be exported. */

Sugerindo que o que quer que esteja lá não está completo.


fonte
5
Aqui, é para uma função, portanto não há questão de exportar nada, pois não há nenhuma execve()chamada de sistema envolvida. Veja zshum shell que suporte funções de chamada com uma matriz temporariamente configurada dessa maneira.
Stéphane Chazelas
@ StéphaneChazelas Mas o ambiente muda (adicionando uma nova variável) e depois reverte para trás, após a função ser concluída (eu sou sobre este caso my_var=one func_bar:). Podemos dizer que isso exportestá contribuindo para o meio ambiente e, portanto, a exportação é usada aqui, sob o capô? Olhe para a minha resposta, eu adicionei o código de demonstração.
MiniMax
10

Na man bashseção BUGS do (a versão do bashé 4.3):

INSETOS

   Array variables may not (yet) be exported.

O próximo código demonstra que existe uma variável temporária no ambiente, apenas enquanto a função está em execução. Quando a função é concluída, a variável temporária desaparece.

### defining the "bar" function
### it pass all environment variables to the "grep" command
### and the "grep" prints the only "my_var" variable from it
bar() { env | grep my_var=; }

### calls the "bar" function with the temporary 
### variable "my_var" created and assigned.
my_var=one bar

my_var=one         ### The output. The environment contains the "my_var" variable

### checks, does the environment still have the "my_var" variable
### (It doesn't have.)
env | grep my_var=
                   ### The output is empty,
                   ### the environment doesn't contain the "my_var" variable

Informação relacionada:

MiniMax
fonte