What is the proper way to test a Bash function's return value?

117,445

Solution 1

If it was the exit code and not the result, you could just use

if func arg; then ...

If you cannot make the function return a proper exit code (with return N), and you have to use string results, use Alex Gitelman's answer.

$ help if:

if: if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi

Execute commands based on conditional.

The if COMMANDS list is executed. If its exit status is zero, then the then COMMANDS list is executed. Otherwise, each elif COMMANDS list is executed in turn, and if its exit status is zero, the corresponding then COMMANDS list is executed and the if command completes. Otherwise, the else COMMANDS list is executed, if present. The exit status of the entire construct is the exit status of the last command executed, or zero if no condition tested true.

Exit Status: Returns the status of the last command executed.

Solution 2

If you need to test two conditions, one being the exit status of function/command and the other e.g. value of variable, use this:

if func arg && [[ $foo -eq 1 ]]; then echo TRUE; else echo FALSE; fi

Solution 3

This error seems to be produced if the function returns more than one word.

For example, 1 2.

Just quote it:

"$(func arg)"

Sample:

$ if [[ 1 2 ]] ; then echo 1 ; fi
-bash: conditional binary operator expected
-bash: syntax error near `2'
$ if [[ "1 2" ]] ; then echo 1 ; fi
1

And if you compare 0 vs non 0, just use

if [[ "$(func arg)" != "0" ]]

Solution 4

On a related note, if the function returns a variety of exit codes instead of true/false, then:

func args; ec=$?      # call function and grab the exit code
                      # it is better to have them on the same line so that a future addition of a command
                      # before the case statement wouldn't break the logic
case $ec in
  value1) # commands
          ;;
  value2) # commands
          ;;
  *)      # commands
          ;;
esac

Solution 5

select provides a lot of help here.

PS3="What's your choice? (^D to stop choosing): "
select mainmenuinput in updatesystem installsamba installvsftpd installwebmin configuresambaforactivedirectory quitprogram; do
    case "$mainmenuinput" in

    "updatesystem")
        echo "Update System..."
    ;;

    "installsamba")
        echo "Installing Samba..."
    ;;

    #echo And so forth...
    esac
done

echo Done

For help with select, consult man bash and search for 'select'. Providing no input will repeat the menu.

select name [ in word ] ; do list ; done
       The  list  of words following in is expanded, generating a list of items.  The set of expanded words is printed on the standard error, each preceded by a number.  If the in word is omitted, the
       positional parameters are printed (see PARAMETERS below).  The PS3 prompt is then displayed and a line read from the standard input.  If the line consists of a number corresponding  to  one  of
       the  displayed  words, then the value of name is set to that word.  If the line is empty, the words and prompt are displayed again.  If EOF is read, the command completes.  Any other value read
       causes name to be set to null.  The line read is saved in the variable REPLY.  The list is executed after each selection until a break command is executed.  The exit status  of  select  is  the
       exit status of the last command executed in list, or zero if no commands were executed.

Sample Output:

[rinzler ~] $ ./test.sh
1) updatesystem                      4) installwebmin
2) installsamba                      5) configuresambaforactivedirectory
3) installvsftpd                     6) quitprogram
What's your choice? (^D to stop choosing): 1
Update System...
What's your choice? (^D to stop choosing): 2
Installing Samba...
What's your choice? (^D to stop choosing):
1) updatesystem                      4) installwebmin
2) installsamba                      5) configuresambaforactivedirectory
3) installvsftpd                     6) quitprogram
What's your choice? (^D to stop choosing):
Done
Share:
117,445

Related videos on Youtube

grok12
Author by

grok12

I'm learning C. I'm going page by page thru K&R and doing almost all the exercises. I'm retired and I'm doing this for fun.

Updated on December 03, 2021

Comments

  • grok12
    grok12 over 2 years

    I would like to test a Bash function's return value in an if statement like this:

    if [[ func arg ]] ; then …
    

    But I get error messages like: conditional binary operator expected.

    What is the right way to do this?

    Is it the following?

     if [[ $(func arg) ]] ; then ...
    
    • deek0146
      deek0146 almost 13 years
      What type of value does the fuction return?
    • grok12
      grok12 almost 13 years
      0 or 1 but it could return something else if that were better.
    • kay
      kay almost 13 years
      I'd recommend using the function's exit code for passing status information.
  • Philipp
    Philipp almost 13 years
  • grok12
    grok12 almost 13 years
    That is great! Hard to believe that the right way is the simplest! My faith in unix/shell/bash/futureofhumanity is amplified!
  • Alex Gitelman
    Alex Gitelman almost 13 years
    @Philipp Good point. I am just used to single [. I corrected the answer to use [[. But I tend to quote everything so in this specific case it probably would not matter.
  • Philipp
    Philipp almost 13 years
    except in the case mentioned in the pitfall where an old shell doesn't interpret LHSes starting with a dash correctly.
  • xdhmoore
    xdhmoore almost 7 years
    Oh yeah. The help command. I always forget about that and end up man spelunking.
  • febot
    febot about 6 years
    How do I test the negated value?
  • kay
    kay about 6 years
    @OndraŽižka, there are no negative return values. The exit code is casted to a uint8_t, e.g. exit -3 -> 256 - 3 = 253
  • febot
    febot about 6 years
    @kay I didn't write negative, I wrote negated. How do you test for a negated value? if !func arg; doesn't work.
  • kay
    kay about 6 years
    @OndraŽižka, ah, you could simply use the else branch.
  • febot
    febot about 6 years
    @kay Right, crossed my mind... if func ; then ; else ...; fi I was hoping for something nicer :) Thanks though.
  • epsilon
    epsilon almost 5 years
    @OndraŽižka a bit late to the party but you can use: if ! func arg; then echo "func returns non zero"; fi mind the space between the negation operator and the function call