22

OS: Ubuntu 16.04.3

Shell: Bash 4.3.48


I know that is possible to temporarily change the content of a variable as in var=value command, being probably IFS= read -r var the most notable case of this.

And, thanks to Greg's wiki, I also understand:

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

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

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

What escapes my understanding is this:

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

As far as I know (and following the logic of previous examples), it should print bar, not (bar baz).

Does this only happen to me? Is this the intended behavior and I'm missing something? Or is this a bug?

12
  • 3
    Perhaps it has something to do with the fact that bash doesn't support arrays as environmental variables?
    – jesse_b
    Dec 21, 2017 at 18:30
  • 3
    @Jesse_b Maybe. Though when I run export var=(foo bar); echo "${var[0]}" it prints foo, not (foo bar).
    – nxnev
    Dec 21, 2017 at 18:35
  • 1
    Odd, that worked for me as well. And using export it shows: declare -ax var=([0]="foo" [1]="bar")
    – jesse_b
    Dec 21, 2017 at 18:39
  • 3
    Environment can't contain arrays, AFAIK. E.g., export i_am_array=(foo bar); /usr/bin/env | grep i_am_array gives no output here.
    – derobert
    Dec 21, 2017 at 18:47
  • 3
    Also: foo() { declare -p var; } ; var=(bar baz) foo gives declare -x var="(bar baz)" confirming its being treated as a string, not an array
    – derobert
    Dec 21, 2017 at 18:49

3 Answers 3

19

Generally calling:

var=value cmd

where cmd is a function is not portable.

With bash, that only works for scalar variables (and with x=(...) parsed as an array but assigned as a scalar) and there are a number of issues with scoping if you do that, with ksh93 and yash, it works but the variable definition remains afterwards. With mksh, you get a syntax error. In the Bourne shell, it didn't work at all, even for scalar variables.

Also note that even with scalar variables, whether the variable ends up being exported within the function (that is, passed to commands being executed) varies from shell to shell (it is in bash, yash, mksh, zsh, but not in ksh, ash).

It only works the way you'd expect with zsh. Note that zsh array indices start at 1.

bash-4.4$ zsh
$ a=(before value)
$ f() echo $a[1]
$ a=(temp value) f
temp
$ echo $a[1]
before
12

It's not just a bug, it seems to be an unimplemented feature with no plans of ever being so. This mailing list post from 2014 has this from the creator:

Fortunately, in bash 4.3 (patchlevel 25), you cannot just -DARRAY_EXPORT and get array variable import/export. The code doesn't compile, and if you fix that, it does not link, and if you fix that, well, you end up with the following issue.

That's a ton of trouble to go through just for this. I don't have any plans to enable array export.

Pulling from the latest git repo for Bash has this in variables.c:

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

Suggesting that whatever is there isn't complete.

2
  • 5
    Here, it's for a function, so there's no question of exporting anything as there's no execve() system call being involved. See zsh for a shell that supports calling functions with an array temporarily set that way. Dec 21, 2017 at 19:50
  • @StéphaneChazelas But the environment changes (by adding a new variable) and then reverts to back, after the function completed (I am about this case: my_var=one func_bar). Can we say, that export is adding to the environment and thus, the exporting is used here, under the hood? Look at my answer, I added the demonstration code.
    – MiniMax
    Dec 22, 2017 at 19:23
10

From the man bash's BUGS section (the version of the bash is 4.3):

BUGS

   Array variables may not (yet) be exported.

The next code demonstrates, that a temporary variable exists in the environment, only while the function is running. When the function is completed, the temporary variable disappears.

### 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

Related information:

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .