4

good day all

after some bash self study and expermenting, I am stuck with returning an array from a function, and for the life of me can't see my error.

in short, what this should/must do is by using a fucntion have a function which reads in values/strings from a file, returning an array:

  • declare and array: clients
  • assign the function's return array to array clients
  • display array clients

It seems to me as if the function reads the whole file and not line by line, thus putting all strings into a single cell in the array, and I am not sure how to explicitly display clients[0] as this $(clients[0]) fails in bash code

If by an means I am doing something incorrectly, please point this out too or any suggestions on optimising this too

#!/bin/bash
readArray(){
        local array=()
        local i=0;
        local j=0
        while IFS= read -r LINE  && [[ -n "$LINE" ]] ; do 
                array[$((i++))]+=${LINE}; # Append line to the array
                ((j++))
        done < "$1";
        rtr=${array[@]}
}
string="/home/cybex/openvpntest/openvpn.log"
declare -a clients
#sed -i '/^$/d' $string
clients=$(readArray "$string")
echo "${clients[@]}"

echo -e "array not empty, displaying array contents\n"

for i in "${!clients[@]}"; do 
  echo "$i: ${clients[$i]}"
done
echo -e "\nfinished displaying contents of array"

cat openvpn.log

something
anotherthing
anotherlineoftext
here is one more line
and lastly
one with 
a few spaces
nice

UPDATE for anyone wanting to see how I resolved this

  • declaring a "global" array with "declare -a clients"
  • function executes, adding values DIRECTLY to the clients array

to display a single index position of an array, ref. last line of code "echo "${clients[0]}" " or any other number >=0

working code:

declare -a clients
readArray(){
        local array=()
        local i=0;
        local j=0
        while IFS= read -r LINE  && [[ -n "$LINE" ]] ; do 
                clients[$((i++))]+=${LINE}; # Append line to the array
                ((j++))
        done < "$1";
}
string="/home/cybex/openvpntest/openvpn.log"
sed -i '/^$/d' $string
readArray "$string"
echo "${clients[@]}"

echo -e "array not empty, displaying array contents\n"

for i in "${!clients[@]}"; do 
  echo "$i: ${clients[$i]}"
done
echo -e "\nfinished displaying contents of array"
echo "${clients[0]}"
4

Already answered here.

You should do a minimal search in google, because this was the first link returned for "bash return array"

Edit:

In bash, functions don't return values. They can return a status (the same as other programs).

So, if you want to return something, you should use global variables that are updated inside your function.

  • I have seen this amongst many others, but this does not make sense to me. What should I be looking for? a return, a declare, what sends the array back? – Cybex Nov 17 '15 at 12:55
  • update: ok that makes sense, I haven;t come across a post mentioning this, thanks – Cybex Nov 17 '15 at 13:12
  • @cybex I think I have an answer. – Anthony Rutledge May 20 at 3:05
  • @AnthonyRutledge what would that answer be? – Cybex May 20 at 7:41
  • @Cybex see my answer below. ;-) – Anthony Rutledge May 20 at 16:39
1

Discussion

If you have come to the point of wanting to return an array from a function, then you are probably aware that you can only return status codes. Boo! You say. :-)

What can we do with other data in a function that we want to use in another function / context?

  1. echo

Assuming stdout is set to the terminal, at least you can see the contents of a variable or something.

  1. Output Redirection: > or >>

Not ideal, but possible. :-) There are probably more things you can do, but let's stop here.

Discussion continued ...

Let us say we think option #1 above sounds promising. What usually happens? Something like this ...

function listToString ()
{
    echo "$*"
}

Reference: Your UNIX: The Ultimate Guide, 2nd Edition, p. 387 (last para).

If I call doSomething, it might, say, send a string message to stdout. That output can be captured in two different ways.

  1. Backticks `doSomething`
  2. This thing: $(doSomthing)

If that is true, then you can save something you send to stdout in another context.

var1=`doSomething`

or

var1=$(doSomething)

In summary ....

Convert a list to a string. Echo the string. Capture the echoed string with command substitution (see above). Use read combined with a here string (<<<) to convert the string into an array. Use array at your leisure.

File: new_users

fsmith
jdoe

Let's say we wanted to add new users with a function we made called addAccounts that loops over username arguments. The order of march would be.

  1. Make file
  2. Read file
  3. Convert list to a string
  4. Convert the string to an array.

    function listToString () { echo "$*" }

    usersString=$(listToString $(cat new_users))

    read -a users <<< $usersString

    addAccounts "${users[@]}"

listToStrig may not work with all lines of input. Test it on your input.

The last line should reslove to:

addAccounts "fsmith" "jdoe"
0

This trick won't always work (When you have values with whitespaces, or you want to return values that depend on input values), but it usually does the work:

array_returning_func() {
    echo "cat dog tree"
}

declare -a arr="$(array_returning_func)"
for obj in ${arr[@]}; do
    echo "$obj"
done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.