0

I have made the following function to calculate the maximum value of an array:

MaxArray(){
aux ="$1"
for n in "$@"
do
    [ "$n" -gt "$aux" ] && aux="$n"
done
return $aux
}

I tried changing return to echo "$aux" to see if it calculated the value correctly and it worked. With an array with the following values: (1, 10, 152, 0, 3), I tried return and called the function like this:

value=$( MaxArray ${array[@]} )
echo "value is $value"

But $value is empty after calling the function. How can I assign the return of the function to $value correctly?

itsLOKO
  • 31
  • 5
  • My answer to a similar question [here](https://stackoverflow.com/questions/72414904/unexpected-output-in-bash-script-function/72417911#72417911) may help... – Gordon Davisson Jun 04 '22 at 10:20
  • Also see [How to return a string value from a Bash function](https://stackoverflow.com/q/3236871/4154375) and [BashFAQ/084 (How do I return a string \(or large number, or negative number\) from a function? "return" only lets me give a number from 0 to 255.)](https://mywiki.wooledge.org/BashFAQ/084). – pjh Jun 04 '22 at 10:45

4 Answers4

3

Replace

return $aux

with

echo "$aux"

Command substitution captures the standard output, not the exit status.

As an aside, variable assignments should not have spaces before or after the equal sign, the assignment should be

aux="$1"
user000001
  • 32,226
  • 12
  • 81
  • 108
3

You don't return a value with return which is used to return an exit status. You return a value by sending it to the standard output (echo, printf...) If your bash is recent enough a better solution that avoids a sub-shell is to pass the variable name as a function argument and use a named reference (local -n var=name):

MaxArray(){
  local -n tmp="$1"
  local -i n
  tmp="$2"
  shift 2
  for n in "$@"; do
    [ "$n" -gt "$tmp" ] && tmp="$n"
  done
}

Then:

$ unset value
$ MaxArray value 1 2 3 4 5 4 3 2 1
$ echo $value
5

Note that if your values are stored in an indexed array you can use the same principle to pass its name instead of its content:

$ MaxArray(){
  local -n tmp="$1"
  local -n arr="$2"
  local -i n
  tmp="${arr[0]}"
  for n in "${arr[@]}"; do
    [ "$n" -gt "$tmp" ] && tmp="$n"
  done
}

$ declare -a values=( 1 2 3 4 5 4 3 2 1 )
$ unset value
$ MaxArray value values
$ echo $value
5
Renaud Pacalet
  • 25,260
  • 3
  • 34
  • 51
2

In the shell, passing values is done through the output, not the return code:

#!/bin/bash

MaxArray() {
    local n aux="$1"
    for n in "$@"
    do
        (( n > aux )) && aux=$n
    done
    echo "$aux"
}

value=$( MaxArray "${array[@]}" )
Fravadona
  • 13,917
  • 1
  • 23
  • 35
2

There are multiple methods for functions to return values:

1st method is to provide the result in a global variable. This method also works for all POSIX-shell variants:

#!/bin/sh

# Here we use the global ret variable to get the result of the function
ret=

max() {
  ret=$1
  shift
  for n
  do
    [ "$n" -gt "$ret" ] && ret=$n
  done
}

max 1 8 2 7 42 23 17

printf 'The maximum of %s is %s\n' '1 8 2 7 42 23 17' "$ret"

The other common method is also POSIX-shell friendly. It involves streaming the result to stdout (printing it), and capturing it into a variable when calling the function. This involves a sub-shell and is to be avoided in a loop for this reason:

#!/bin/sh

max() {
  gtst=$1
  shift
  for n
  do
    [ "$n" -gt "$gtst" ] && gtst=$n
  done
  # Print the result
  printf %s "$gtst"
}

# Capture the printout of max into the ret variable
ret=$(max 1 8 2 7 42 23 17)

printf 'The maximum of %s is %s\n' '1 8 2 7 42 23 17' "$ret"

The third method involves addressing a variable indirectly by its name, using eval:

#!/bin/sh

max() {
  # Get the name of the return variable
  ret_name=$1
  shift
  gtst=$1
  shift
  for n
  do
    [ "$n" -gt "$gtst" ] && gtst=$n
  done
  # Evaluate expression to assign returned value to provided variable name
  eval "$ret_name=$gtst"
}

# will get the result into the variable ret
max ret 1 8 2 7 42 23 17

# shellcheck disable=SC2154 # dynamically referrenced ret
printf 'The maximum of %s is %s\n' '1 8 2 7 42 23 17' "$ret"

Finally this method use nameref variables which are only available to Bash starting at version 4.2:

#!/bin/bash

max() {
  # Get the name of the return variable into a nameref variable
  local -n gtst=$1
  local -i n
  shift
  gtst=$1
  shift
  for n
  do
    declare -p gtst
    [ "$n" -gt "$gtst" ] && gtst=$n
  done
}

# will get the result into the variable ret
declare -i ret
max ret 1 8 2 7 42 23 17

# shellcheck disable=SC2154 # dynamically referrenced ret
printf 'The maximum of %s is %s\n' '1 8 2 7 42 23 17' "$ret"

Same output for all versions:

The maximum of 1 8 2 7 42 23 17 is 42
Léa Gris
  • 17,497
  • 4
  • 32
  • 41