3

I am trying modify an array that I have passed as a parameter to a function. So far, I have an empty array outside of the function:

buckets=()

Then I have the function which takes in 2 arguments. The first argument is the empty array that I want to fill. The second argument is the name of the file that contains the data I want to use to fill the array.

So far, what I have done is create a temporary array. Then fill the temporary array with the contents of the file. This is how I do that:

fillarray ()
{
# Declare the paramater as a temporary array
declare -a tempArray=("${!1}")

# Fill it up
while IFS= read -r entry; do
  tempArray+=("$entry")
done < <(jq -r '.data | .[].name' $2)

The final step is to set the parameter array(aka buckets) to be the contents of the temporary array which we just filled up. Any suggestions on how to go about doing this?

2
  • if your tempArray has what you need, then copying it to the buckets array will be easy like: Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux'); Linux=("${Unix[@]}"); echo ${Linux[@]}; See this for more operations: thegeekstuff.com/2010/06/bash-array-tutorial ---OR see this to copy array to another stackoverflow.com/questions/19417015/… Commented Jan 29, 2015 at 20:20
  • @ArunSangal The example you give works if I have and know variable names. My issue is with generic parameters inside a function that modify a variable outside of the function. I am trying to refactor my code so I don't have to repeat myself. That is why I am trying to capture this fillarray as a function and pass in the array I want to fill up. Thank you for the tutorials. I will read them to become more familiar with bash. Commented Jan 29, 2015 at 20:36

2 Answers 2

8

In BASH 4.3+ you can just pass an array by named reference. So your function can be simplified to:

fillarray() {
   # tempArray is a reference to array name in $1
   local -n tempArray="$1"
   while IFS= read -r entry; do
      tempArray+=("$entry")
   done < <(jq -r '.data | .[].name' "$2")
}

Then call it as:

buckets=()
fillarray buckets file.json

And test it as:

declare -p buckets

EDIT: To make it work on BASH 3.2 use below snippet:

fillarray() {
   # $2 is current length of the array
   i=$2
   while IFS= read -r entry; do
      read ${1}"[$i]" <<< "$entry"
      ((i++))
   done < <(jq -r '.data | .[].name' "$3")
}

Then call it as:

buckets=()
fillarray buckets ${#buckets[@]} file.json
Sign up to request clarification or add additional context in comments.

2 Comments

This worked. Just to clarify, do you think you could explain what the <<< and the double parenthesis around i++ means? And also why we don't have to put a $ before the i when we increment it?
((i++)) is BASH arithmetic to increment i and <<< is called here-string in BASH to feed $entry to ${1}"[$i]" where ${1} is the name of array and "[$i]" is the array index in read command
0

Another way via eval,

fillarray () {
 local tempArray;

 while IFS= read -r entry; do
    tempArray[${#tempArray[@]}]="$entry";
 done < <(jq -r '.data | .[].name' $2);

 eval $1=\('"${tempArray[@]}"'\);
}

2 Comments

When I did a bit of research, I found this as a possible solution. Many claim it works, but I don't really understand how. What is the eval doing that makes it so... special? I also read that this might lead to some security issues? I'm not sure how, but if I can understand what the eval is doing, then I could see how security might be an issue. bash is weird.
If $1 contains, as an example, "buckets"; the eval code is equivalent to buckets=(${tempArray[@]}), that is tempArray is copied into buckets array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.