¿Posible error en Bash ?: foo () {echo “$ {var [0]}”; }; var = (bar baz) foo

22

SO : Ubuntu 16.04.3

Shell : Bash 4.3.48


Sé que es posible cambiar temporalmente el contenido de una variable como en var=value command, siendo probablemente IFS= read -r varel caso más notable de esto.

Y, gracias a la wiki de Greg , también entiendo:

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

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

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

Lo que se me escapa es esto:

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

Hasta donde yo sé (y siguiendo la lógica de los ejemplos anteriores), debería imprimir bar, no (bar baz).

¿Esto solo me pasa a mí? ¿Es este el comportamiento previsto y me falta algo? ¿O es esto un error?

nxnev
fuente
3
¿Quizás tiene algo que ver con el hecho de que bash no admite matrices como variables ambientales?
Jesse_b
3
@Jesse_b Quizás. Aunque cuando lo ejecuto export var=(foo bar); echo "${var[0]}"imprime foo, no (foo bar).
nxnev
1
Extraño, eso también funcionó para mí. Y usarlo exportmuestra:declare -ax var=([0]="foo" [1]="bar")
Jesse_b
3
El entorno no puede contener matrices, AFAIK. Por ejemplo, export i_am_array=(foo bar); /usr/bin/env | grep i_am_arrayno da salida aquí.
derobert
3
También: foo() { declare -p var; } ; var=(bar baz) fooda declare -x var="(bar baz)"lo que confirma su ser tratada como una cadena, no una matriz
Derobert

Respuestas:

19

Generalmente llamando:

var=value cmd

donde cmdes una función no es portátil.

Con bash, eso solo funciona para variables escalares (y con x=(...)analizado como una matriz pero asignado como escalar) y hay una serie de problemas con el alcance si lo hace, con ksh93y yash, funciona, pero la definición de la variable permanece después. Con mksh, obtienes un error de sintaxis. En el shell Bourne, no funcionó en absoluto, incluso para las variables escalares.

También tenga en cuenta que incluso con variables escalares, si la variable termina siendo exportada dentro de la función (es decir, se pasa a los comandos que se ejecutan) varía de shell a shell (está en bash, yash, mksh, zsh, pero no en ksh, ceniza).

Solo funciona de la manera que esperarías zsh. Tenga en cuenta que los zshíndices de matriz comienzan en 1.

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

No es solo un error, parece ser una característica no implementada sin planes de serlo. Esta publicación de la lista de correo de 2014 tiene esto del creador:

Afortunadamente, en bash 4.3 (patchlevel 25), no puede simplemente -DARRAY_EXPORT y obtener la importación / exportación de variables de matriz. El código no se compila, y si lo arreglas, no se vincula, y si lo arreglas, bueno, terminas con el siguiente problema.

Eso es un montón de problemas por los que pasar solo por esto. No tengo ningún plan para habilitar la exportación de matrices.

Aprovechando el último repositorio de git para Bash tiene esto en variables.c:

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

Sugiriendo que lo que sea que esté allí no está completo.


fuente
55
Aquí, es para una función, por lo que no se trata de exportar nada, ya que no hay execve()llamadas al sistema involucradas. Busque zshun shell que admita funciones de llamada con una matriz configurada temporalmente de esa manera.
Stéphane Chazelas
@ StéphaneChazelas Pero el entorno cambia (al agregar una nueva variable) y luego vuelve a atrás, una vez completada la función (estoy a punto de este caso:) my_var=one func_bar. ¿Podemos decir que se exportestá agregando al medio ambiente y, por lo tanto, la exportación se utiliza aquí, bajo el capó? Mira mi respuesta, agregué el código de demostración.
MiniMax
10

Desde la man bashsección de ERRORES (la versión de la bashes 4.3):

LOCO

   Array variables may not (yet) be exported.

El siguiente código demuestra que existe una variable temporal en el entorno, solo mientras la función se está ejecutando. Cuando se completa la función, la variable temporal 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

Información relacionada:

MiniMax
fuente