0

I have a small problem in here with bash I wrote an array in a simple function and I need to return it as an array with read command and also need to call it somehow.

function myData {
    echo 'Enter the serial number of your items : '
    read -a sn
    return ${sn[@]}
}

for example like this ???

$ ./myapp.sh
Enter the serial number of your items : 92467 90218 94320 94382

myData    
echo ${?[@]}

Why we don't have return value in here like other languages ? thanks for your help...

Freeman
  • 9,464
  • 7
  • 35
  • 58
  • 1
    Have a look at [Return value in a Bash function](https://stackoverflow.com/q/17336915/3266847) to understand the meaning of `return` in Bash – it's meant to convey exit status, not to return data from a function. – Benjamin W. Dec 04 '19 at 21:41
  • thnx a lot do you have any suggestion to return data please? (in my example) – Freeman Dec 04 '19 at 21:46
  • 2
    You *don't*. You either set a global variable, or you write to standard output and capture that with a command substitution. – chepner Dec 04 '19 at 21:58
  • the simplest example is `myfunc() { echo got input as $@ ; } ; var=$(myfunc some text); echo "$var"` . Good luck. – shellter Dec 04 '19 at 22:54
  • Is `myData` going to use the input (92467 ...), or `read` from stdin ? – dash-o Dec 05 '19 at 02:11

1 Answers1

3

As others mention, the builtin command return is intended to send the exit status to the caller.
If you want to pass the result of processing in the function to the caller, there will be several ways:

  1. Use standard output

    If you write something to the standard output within a function, the output is redirected to the caller. The standard output is just a non-structured stream of bytes. If you want to make it have a special meaning such as an array, you need to define the structure by assigning a delimiter to some character(s). If you are sure each element do not contain space, tab, or newline, you can rely on the default value of IFS:

    myfunc() {
        echo "92467 90218 94320 94382"
    }
    
    ary=( $(myfunc) )
    for i in "${ary[@]}"; do
        echo "$i"
    done
    

    If the elements of the array may contain whitespace or other special characters and you need to preserve them (such a case as you are handling filenames), you can use the null character as the delimiter:

    myfunc() {
        local -a a=("some" "elements" "contain whitespace" $'or \nnewline')
        printf "%s\0" "${a[@]}"
    }
    
    mapfile -d "" -t ary < <(myfunc)
    for i in "${ary[@]}"; do
        echo ">$i"           # The leading ">" just indicates the start of each element
    done
    
  2. Pass by reference

    As other languages, bash>=4.3 has a mechanism to pass the variable by reference or by name:

    myfunc() {
        local -n p="$1"     # now p refers to the variable with the name of value of $1
        for (( i=0; i<${#p[@]}; i++ )); do
            ((p[i]++))      # increment each value
        done
    }
    
    ary=(0 1 2)
    myfunc "ary"
    echo "${ary[@]}"        # array elements are modified
    
  3. Use the array as a global variable

    Will be needless to explain its usage and pros/cons.

Hope this helps.

tshiono
  • 21,248
  • 2
  • 14
  • 22
  • thanks a lot, but as I mentioned in my title what about read command, may I ask you give me an example with read command ? I want to get array from read command in function. – Freeman Dec 05 '19 at 07:51
  • Sorry for my insufficient explanation. In your case, just say `echo "${sn[@]}"` and split into an array within the caller. Or you don't even have to generate an array in the function and just `echo` the space-separated string then let the caller split it. Have I made myself clear? – tshiono Dec 05 '19 at 08:09
  • thanx it was perfect, but I don't want to do this, I think this way is not very nice, let me sleep on it and search more, if I couldn't find another solution I'll use your method rep ++ – Freeman Dec 05 '19 at 09:36
  • All right. If you find a better way, I'd be happy to know about it. Good luck! – tshiono Dec 05 '19 at 10:40