Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash arrays created by sourcing inside a function have local scope but scalars are global

Consider the following bash script:

#!/usr/bin/env /bin/bash

function sourcefile(){
  source /tmp/srcfile
  echo "Sourced array in func: ${sourcedarray[*]}"
  echo "Sourced scalar in func: ${sourcedscalar}"
}

globalarray=([0]="xyzzy" [1]="kaboom")
globalscalar="argle"

cat >/tmp/srcfile <<EOF
export sourcedscalar="bargle"
export sourcedarray=([0]="foo" [1]="bar")
EOF

sourcefile

echo "Global array: ${globalarray[*]}"
echo "Global scalar: ${globalscalar}"
echo "Sourced array: ${sourcedarray[*]}"
echo "Sourced scalar: ${sourcedscalar}"

One would reasonably expect all four values to be set in the output, but at least with bash version 3.2.57(1)-release (yes, yes I know: we all pay for Apple's paranoia) that is not the case:

Sourced array in func: foo bar
Sourced scalar in func: bargle
Global array: xyzzy kaboom
Global scalar: argle
Sourced array:
Sourced scalar: bargle

As far as I can tell:

  • a scalar variable created in a function by sourcing a file is created in global scope
  • but an array variable created in a function by sourcing a file is created in local scope, and exporting it does not change this

This seems inconsistent to put it mildly: is there some way to work around this behavior?

like image 614
Doctor Memory Avatar asked Mar 28 '21 20:03

Doctor Memory


1 Answers

As pointed out in the comments, in more "recent" version of bash this is no longer a problem. For versions 4.3 and below we find the following:

First of all, whether or not the assignment is in a sourced script plays no role; the function makes a difference. However, the function alone also doesn't cause your problem. Only the combination of function + export causes the array to be local.

If you remove the export in front of the assignment, everything works fine. In your example you don't have to export the variables anyway. Actually, there is no way to export an array as arrays are not specified in posix.

If you want to create a global variable and also export it then use declare -xg instead of export.

#!/usr/bin/env bash

function sourcefile(){
  source /tmp/srcfile
  echo "Sourced array in func: ${sourcedarray[*]}"
  echo "Sourced scalar in func: ${sourcedscalar}"
}

globalarray=([0]="xyzzy" [1]="kaboom")
globalscalar="argle"

cat >/tmp/srcfile <<EOF
declare -xg sourcedscalar="bargle"
# whether or not you use `-x` makes no difference for the environment
declare -xga sourcedarray=([0]="foo" [1]="bar")
EOF

sourcefile

echo "Global array: ${globalarray[*]}"
echo "Global scalar: ${globalscalar}"
echo "Sourced array: ${sourcedarray[*]}"
echo "Sourced scalar: ${sourcedscalar}"
like image 74
Socowi Avatar answered Oct 14 '22 05:10

Socowi