Nate Houk
Nate Houk

Reputation: 365

How to compare result of function in if statement using idiomatic bash

I have a function which returns one of three values, 0, 1 or 2

I want to check the return value of the function in an if statement.

How can I do this in idiomatic bash?

This works, but looks very wrong to me:

vercomp $prev $new
result=$?
if [[ result -eq 1 ]]; then
  echo "Greater than" 
elif [[ result -eq 2 ]]; then
  echo "Less than"
fi

How can I consolidate this code and use the function directly in the if statement instead of using the intermediate result variable and how can I access the return value without using $? ?

Everything I have tried has failed.

For example even this fails - why?

result=vercomp $prev $new
if [[ result -eq 1 ]]; then
  echo "Greater than" 
elif [[ result -eq 2 ]]; then
  echo "Less than"
fi

And this fails:

if [[ vercomp $prev $new -eq 1 ]]; then
  echo "Greater than" 
elif [[ vercomp $prev $new -eq 2 ]]; then
  echo "Less than"
fi

This fails:

if [[ $(vercomp $prev $new) -eq 1 ]]; then
  echo "Greater than" 
elif [[ $(vercomp $prev $new) -eq 2 ]]; then
  echo "Less than"
fi

What am I doing wrong? How can I improve my working code?

Upvotes: 3

Views: 1525

Answers (2)

Inian
Inian

Reputation: 85590

Bash functions return exit codes back to the shell which can be retrieved from the value of $? as in your first case. You need to read through Return value in a Bash function to understand the difference between exit code and return value from function.

As explained in detail in multiple answers including Function return values within BASH if statements you can directly use the function invocation in the if statement. A return code of 0 from the function would assert the if condition to true. So you can do something like

if vercomp "$prev" "$new"; then
    printf 'return code zero \n'
else
    case $? in
      1) printf 'return code one \n' ;;
      2) printf 'return code two \n' ;;
      *) printf "unknown return code $?\n" ;;
    esac
fi

As for the failure cases

  1. This result=vercomp $prev $new is not even a valid function execution in bash but an incorrect variable assignment. To run function and store the output in a variable, you need to use Command Substitution $(..) You need to have written it as result=$(vercomp "$prev" "$new")
  2. And if [[ vercomp $prev $new -eq 1 ]]; then again is an incorrect invocation of the function. Everything inside [[..]] is evaluated in a string context. So the test operator [[ just treats it as incorrect operation and would have thrown a parser error
  3. [[ $(vercomp $prev $new) -eq 1 ]] is also incorrect. All commands in bash return an exit code to the shell the program is invoked from. The command substitution inherently returns the code to the shell via $? but the -eq operator checks for a string value returned from the invocation. Since the construct does not put any contents to stdout, there won't anything to match with 1 or 2. If you done soemthing like [[ $(vercomp "$prev" "$new"; printf "$?") -eq 1 ]] it would have worked, but again not a good practice.

Upvotes: 2

Cyrus
Cyrus

Reputation: 88646

With bash:

case $? in
  0) echo "one";;
  1) echo "two";;
  2) echo "three";;
esac

See: help case

Upvotes: 1

Related Questions