测试bash函数返回值的正确方法是什么?


72

我想在这样的if语句中测试bash函数的返回值:

if [[ func arg ]] ; then

但我收到如下错误消息: conditional binary operator expected.

什么是正确的方法?

是吗:

 if [[ $(func arg) ]] ; then ...

函数返回什么类型的值?
deek0146 2011年

0或1,但如果更好,它可能会返回其他内容。
grok12 2011年

1
我建议使用该函数的退出代码来传递状态信息。

Answers:


81

如果是退出代码而不是结果,则可以使用

if func arg; then ...

如果无法使函数返回正确的退出代码(带有return N),并且必须使用字符串结果,请使用@Alex Gitelman答案。

$ help if

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

根据条件执行命令。

if COMMANDS列表已执行。如果其退出状态为零,则 then COMMANDS执行列表。否则,elif COMMANDS将依次执行每个列表,如果其退出状态为零,则将then COMMANDS执行相应的 列表,并且if命令将完成。否则,将else COMMANDS执行列表(如果存在)。整个构造的退出状态是最后执行的命令的退出状态,如果没有条件测试为真,则为零。

退出状态:返回上一次执行的命令的状态。


2
太棒了!很难相信正确的方法是最简单的!我对unix / shell / bash /人类未来的信念得到了增强!
grok12 2011年

3
如何测试负值?
OndraŽižka18年

2
@kay我没有写负面的,我写的是否定的。您如何测试负值?if !func arg; 不起作用。
OndraŽižka,

1
@kay对,我想了一下...if func ; then ; else ...; fi 我希望有更好的东西:)不过谢谢。
OndraŽižka18年

1
@OndraŽižka参加聚会有点晚,但是您可以使用:if ! func arg; then echo "func returns non zero"; fi注意求反运算符和函数调用之间的空间
epsilon

20

这对我很有用,因此我将添加以下详细信息。

如果需要测试两个条件,一个条件是功能/命令的退出状态,另一个条件是变量的值,请使用以下条件:

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

18

如果函数返回多个单词,则似乎会产生此错误。

例如,1 2

引用一下即可:

"$(func arg)"

样品:

$ 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

如果比较0与非0,请使用

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


@Philipp好点。我只是单身[。我更正了使用[[的答案。但是我倾向于引用所有内容,因此在这种特定情况下可能没关系。
Alex Gitelman

除了在陷阱中提到的情况(旧的shell无法正确解释以破折号开头的LHS)之外,其他情况除外。
菲利普

1

与此相关的是,如果函数返回各种退出代码而不是true / false,则:

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

1

意识到这是一个老帖子...这是我对此事的建议:

select 在这里提供了很多帮助。

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

如需有关的帮助select,请咨询man bash并搜索“选择”。不提供任何输入将重复菜单。

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.

样本输出:

[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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.