Before explaining my bash problem let me give you some context:
I am writing some scripts using a bash “framework” we use at my current job. One of the feature of the framework is to init a sets of environments variables useful to run jobs on our cluster infrastructure.
These variables depend on a date specified by $YY, $mm and $dd which are also environment variables (yes, this is wired). To use the framework you start by defining the date and then you call a function to init other vars. This works fine when you write scripts that need variables for a specific day only. Today I am writing something which needs variables for 2 different days. Writing this I face a strange issue. For you to better understand the problem I wrote this code that simulate it:
#!/bin/bash
function assign(){
date=$1
date[1]=$YY
date[2]=$mm
date[3]=$dd
}
function display() {
date=$1
echo "${date[1]}/${date[2]}/${date[3]}"
}
export YY=2012
export mm=09
export dd=20
declare -a my_date1=()
assign $my_date1
export YY=2012
export mm=08
export dd=20
declare -a my_date2=()
assign $my_date2
display $my_date1
display $my_date2
The expected output is:
2012/09/20
2012/08/20
But the output is:
2012/08/20
2012/08/20
At first I thought that the assign function filled the array with reference to $YY, $mm and $dd instead of their values. But then I try with the following code and it doesn’t change the result.
date[1]=$(echo $YY)
date[2]=$(echo $mm)
date[3]=$(echo $dd)
Can somebody explain me what append?
Maybe something wired with date=$1…
Arrays are not passed by either value or reference in bash. Rather, the value of the expansion of the array is passed by value. When you write
the
datevariable insideassignis null, since$my_date1expands to an empty string and disappears after word-splitting before the function is called. As a result,$1is unset.But
date, being a global variable because it was not declared as local, is set correctly usingYYet al, then reset on the second call toassign.Also, note that the first line of your functions does not make
datea reference to the argument; it’s really just setting the 0th element of what becomes the globaldatearray to the expansion of$1.Having said I’ll that, I’ll show you a way to fake it using the
declarebuilt-in and indirect parameter expansion.