10

I am making a bash script and I have encountered a problem. So let's say I got this

function create_some_array(){
  for i in 0 1 2 3 .. 10
  do
    a[i]=$i
  done
}

create_some_array
echo ${a[*]}

Is there any way I can make this work? I have searched quite a lot and nothing I found worked. I think making the a[] a global variable should work but I can't find something that actually works in my code. Is there any way to return the array from the function to main program?

Thanks in advance

11
  • 2
    This code works without any problems. Do not invent code to show the problem. Show us actual code that is causing the problem. Commented Feb 12, 2013 at 18:30
  • Welcome to Stack Overflow. Please improve your question by posting all relevant error messages exactly as they appear. Also, make sure to include a properly-formatted sample of your expected output so folks understand the results you're trying to achieve. Commented Feb 12, 2013 at 18:32
  • @depesz: I half-agree. I think the asker should "invent code to show the problem" -- but (s)he has to make sure that it is (as you put it) "actual code that is causing the problem". This is known as an SSCCE -- a short, self-contained, correct (compilable) example. Commented Feb 12, 2013 at 18:37
  • @ruakh: well, he/she has the code that is causing the problem. It's just that his invented version for showing it - doesn't contain problems. Unfortunately it's very common (at least on IRC) that people have problem with something, but show something different. Commented Feb 12, 2013 at 18:39
  • 1
    "won't work" is not a technical description. Try running your script with bash -x script_name which will trace what is happening. Commented Feb 12, 2013 at 18:52

6 Answers 6

5

This won't work as expected when there are whitespaces in the arrays:

function create_some_array() {
    local -a a=()
    for i in $(seq $1 $2); do
        a[i]="$i $[$i*$i]"
    done
    echo ${a[@]}
}

and worse: if you try to get array indices from the outside "a", it turns out to be a scalar:

echo ${!a[@]}

even assignment as an array wont help, as possible quoting is naturally removed by the echo line and evaluation order cannot be manipulated to escape quoting: try

function create_some_array() {
...
    echo "${a[@]}"
}

a=($(create_some_array 0 10))
echo ${!a[@]}

Still, printf seems not to help either:

function create_some_array() {
...
    printf " \"%s\"" "${a[@]}"
}

seems to produce correct output on one hand:

$ create_some_array 0 3; echo
 "0 0" "1 1" "2 4" "3 9"

but assignment doesn't work on the other:

$ b=($(create_some_array 0 3))
$ echo ${!b[@]}
0 1 2 3 4 5 6 7

So my last trick was to do assignment as follows:

$ eval b=("$(create_some_array 0 3)")
$ echo -e "${!b[@]}\n${b[3]}"
0 1 2 3
3 9

Tataaa!

P.S.: printf "%q " "${a[@]}" also works fine...

Sign up to request clarification or add additional context in comments.

1 Comment

annoying! this works but my IDE is given me an error that it wont suppress ... parsing stopped here. Invalid use of parantheses? .. annoying but +1
3

This works fine as described. The most likely reason it doesn't work in your actual code is because you happen to run it in a subshell:

cat textfile | create_some_array
echo ${a[*]}

would not work, because each element in a pipeline runs in a subshell, and

myvalue=$(create_some_array)
echo ${a[*]}

would not work, since command expansion happens in a subshell.

1 Comment

j=ls -i "$i" | awk '{print $1}'; inode[count]=$j; This is the part i insert into an array. And when I try to echo this outside the function it dosnt work
3

You can make an array local to a function, and then return it:

function create_some_array(){
    local -a a=()
    for i in $(seq $1 $2); do
        a[i]=$i
    done
    echo ${a[@]}
}

declare -a a=()

a=$(create_some_array 0 10)

for i in ${a[@]}; do
   echo "i = " $i
done

Comments

3

Hi here is my solution:

show(){
    local array=()
    array+=("hi")
    array+=("everything")
    array+=("well?")
    echo "${array[@]}"
}

for e in $(show);do
    echo $e
done

Try this code on: https://www.tutorialspoint.com/execute_bash_online.php

2 Comments

this works +1 but its kinda annoying coz if u dump the length of the array it is always 1 - my IDE warns me its converted it to a string and the console output agrees
Add a space to one of your array elements and you'll find this doesn't work any more.
0

Both these work for me with sh and bash:

arr1=("192.168.3.4" "192.168.3.4" "192.168.3.3")

strArr=$(removeDupes arr1) # strArr is a string
for item in $strArr; do arr2+=("$item"); done # convert it to an array
len2=${#arr2[@]} # get array length
echo "${len2}" # echo length

eval arr3=("$(removeDupes arr1)") # shellcheck does not like this line and won't suppress it but it works
len3=${#arr3[@]} # get array length
echo "${len3}" # echo length

As an aside, the removeDupes function looks like this:

removeDupes() {
  arg="$1[@]"
  arr=("${!arg}")
  len=${#arr[@]}
  resultArr=()
  # some array manipulation here
  echo "${resultArr[@]}"
}

This answer is based on but better explains and simplifies the answers from @Hans and @didierc

Comments

0

Your function doesn't return an array. It creates a global array variable called $a.

function create_some_array(){
  for i in 0 1 2 3 .. 10
  do
    a[i]=$i
  done
}

To return an array:

function create_some_array(){
  local a
  for i in 0 1 2 3 .. 10; do
    a[i]=$i
  done
  printf "%s\n" "${a[@]}"
}

# capture the created array:
readarray -t my_array < <(create_some_array)

# print its elements
for element in "${my_array[@]}"; do
  echo "  - ${element}"
done

This method, doesn't just simulate a returned array, but it also respects the spaces in a particular element.

Hope it helps

Edit: To handle returning an empty array

If you have some logic in your function that requires you to return an empty array, the above will cause an array with a single element \n to be returned. You may not want this.

To get around this, you can simply wrap the printf around a check for if the array is empty like so:

function create_some_array(){
  local a
  for i in 0 1 2 3 .. 10; do
    a[i]=$i
  done
  if [[ ${#a[@]} != 0 ]]; then
    printf "%s\n" "${a[@]}"
  fi
}

Comments

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.