从Bash函数返回布尔值


211

我想编写一个bash函数,检查文件是否具有某些属性并返回true或false。然后,我可以在脚本中的“ if”中使用它。但是我应该返回什么?

function myfun(){ ... return 0; else return 1; fi;}

然后我像这样使用它:

if myfun filename.txt; then ...

当然这是行不通的。如何做到这一点?


3
删除function关键字myfun() {...}就足够了
glenn jackman 2011年

2
重要的ifmyfun:如果以myfun退出0then ...则执行零退出状态;如果是其他情况, else ...则执行。
Eelvex 2011年

7
@nhed:function关键字是一种bashism,将在其他一些shell中引起语法错误。基本上,它是不必要的还是禁止的,那么为什么要使用它呢?它甚至没有作为grep目标的用处,因为它可能不存在(()取而代之的是grep )。
Gordon Davisson

3
@戈登·戴维森:什么?还有其他贝壳吗?;-)
nhed 2013年

请不要使用0和1。请参阅stackoverflow.com/a/43840545/117471
Bruno Bronosky

Answers:


333

使用0表示true,使用1表示false。

样品:

#!/bin/bash

isdirectory() {
  if [ -d "$1" ]
  then
    # 0 = true
    return 0 
  else
    # 1 = false
    return 1
  fi
}


if isdirectory $1; then echo "is directory"; else echo "nopes"; fi

编辑

从@amichair的评论来看,这些也是可能的

isdirectory() {
  if [ -d "$1" ]
  then
    true
  else
    false
  fi
}


isdirectory() {
  [ -d "$1" ]
}

4
不,您不需要这样做-请参阅示例。
Erik

46
为了获得更好的可读性,您可以使用“ true”命令(不执行任何操作并成功完成,即返回0)和“ false”命令(不执行任何操作并成功完成,即返回非零值)。另外,以没有显式return语句结束的函数返回最后执行的命令的退出代码,因此在上面的示例中,函数主体可以简化为only [ -d "$1" ]
amichair

24
Bengt:当您将其视为“错误代码”时,这是有道理的:错误代码0 =一切正常= 0错误;错误代码1 =此调用应该执行的主要操作失败;否则:失败!在手册页中查找。
飞羊

7
当您考虑到编程中的事物通常只能以一种方式成功,而可能以无限的方式失败时,这才有意义。好吧,也许不是无限的,但很多时候,我们的赔率堆积如山。成功/错误不是布尔值。我认为这是“使用0表示真,使用1表示假”。应该读为“使用0表示成功,使用非零表示失败”。
达沃斯

6
请不要使用0和1。请参阅stackoverflow.com/a/43840545/117471
Bruno Bronosky

166

尽管有250多个否决的答案,但为什么您仍然应该关心我所说的话

这并不是说0 = true1 = false。它是:零表示无故障(成功)非零表示故障(类型N)

虽然所选答案从技术上讲是“ true”,但不要return 1在代码中输入**来表示false。它将有一些不幸的副作用。

  1. 有经验的开发人员会发现您是业余爱好者(出于以下原因)。
  2. 有经验的开发人员不这样做(出于以下所有原因)。
  3. 这容易出错。
    • 即使是经验丰富的开发人员,也可能将0和1分别误认为是false和true(由于上述原因)。
  4. 它需要(或将鼓励)多余和荒谬的评论。
  5. 实际上,它没有隐式返回状态有用。

学习一些bash

bash的手册说(重点煤矿)

返回[n]

使Shell函数停止执行并将值n返回给其调用方。如果未提供n,则返回值是函数中最后执行命令退出状态

因此,我们不必永远使用0和1来表示True和False。他们这样做的事实本质上是微不足道的知识,仅对调试代码,面试问题和引起新手的想法有用。

bash手册还说

否则,函数的返回状态是最后执行的命令退出状态

bash手册还说

$?)扩展为最近执行的前台管道退出状态

等等 管道?让我们再翻一遍bash手册

流水线是由一个或多个控制运算符'|'分隔的命令序列 或“ |&”。

是。他们说1条命令是一条管道。因此,所有这三个引号都说相同的话。

  • $? 告诉你最后发生了什么。
  • 起泡了。

我的答案

因此,虽然@Kambus演示了具有如此简单的功能,但没有return根本不需要。与大多数将要阅读此书的人的需求相比,我认为这是不切实际的简单。

为什么 return

如果一个函数要返回其最后一个命令的退出状态,为什么要使用它return呢?因为它导致函数停止执行。

在多种情况下停止执行

01  function i_should(){
02      uname="$(uname -a)"
03
04      [[ "$uname" =~ Darwin ]] && return
05
06      if [[ "$uname" =~ Ubuntu ]]; then
07          release="$(lsb_release -a)"
08          [[ "$release" =~ LTS ]]
09          return
10      fi
11
12      false
13  }
14
15  function do_it(){
16      echo "Hello, old friend."
17  }
18
19  if i_should; then
20    do_it
21  fi

我们这里有...

Line 04是一个显式的[-ish]返回true,因为&&仅当LHS为true时才执行RHS

09返回与行状态匹配的真或假08

13因行而返回false12

(是的,可以打高尔夫球,但是整个示例都是人为设计的。)

另一个常见的模式

# Instead of doing this...
some_command
if [[ $? -eq 1 ]]; then
    echo "some_command failed"
fi

# Do this...
some_command
status=$?
if ! $(exit $status); then
    echo "some_command failed"
fi

请注意,设置status变量如何使的含义神秘化$?。(当然,您知道这$?是什么意思,但是知识渊博的人总有一天会需要Google的帮助。除非您的代码进行高频交易,否则请表现出一些爱心,并设置变量。)但是,真正的收获是“如果不存在状态”或相反的“如果退出状态”可以大声读出并解释其含义。但是,最后一个可能有点过于雄心勃勃,因为看到这个词exit可能会让您认为它正在退出脚本,而实际上却正在退出$(...)子外壳。


**如果您绝对坚持使用return 1false,那么建议您至少使用return 255代替。这将导致您未来的自我,或任何其他必须维护您的代码的开发人员质疑“为什么是255?” 这样,他们至少会引起注意,并更有机会避免犯错。


1
@ZeroPhase 1&0为false和true将是可笑的。如果您具有二进制数据类型,则没有理由。您在bash中处理的是一个状态代码,该状态代码反映成功(单数)和失败(复数)。这是“ if成功做到这一点,else做到这一点”。成功是什么?可能正在检查true / false,可能正在检查字符串,整数,文件,目录,写权限,glob,regex,grep或其他任何会失败的命令。
Bruno Bronosky

3
避免仅因为0/1的钝角和易于混淆而避免将其标准用作返回值是愚蠢的。整个外壳语言是晦涩的,容易混淆。Bash本身truefalse命令使用0/1 = true / false约定。也就是说,关键字的true字面意义为状态码0。另外,if-then语句本质上是对布尔值而不是成功代码进行操作。如果在布尔运算期间发生错误,则该错误不应返回true或false,而只是中断执行。否则,您会得到假阳性(双关语)。
Beejor

1
“如果!$(退出$ status);然后“-应该得到更好的解释。这不是直观的。我必须考虑程序是否在打印消息之前退出。您其余的答案都不错,但是却糟透了。
Craig Hicks

1
@BrunoBronosky我阅读了您的答案,我想我了解内容管道(stdin-> stdout)与返回值中的错误代码之间的区别。但是,我不明白为什么return 1应该避免使用。假设我有一个validate功能,我认为return 1验证失败是合理的。毕竟,如果脚本处理不当(例如,当使用set -e)时,这就是停止脚本执行的原因。
JepZ

1
@Jepz这是一个很好的问题。您是正确的,return 1是有效的。我担心的是这里的所有评论都说“ 0 = true 1 = false是[插入否定词]”。这些人可能有一天会阅读您的代码。因此,对于他们来说,看到return 255(或42甚至2)应该帮助他们更多地思考它,而不要将其误认为“真实”。set -e仍然会抓住它。
布鲁诺·布鲁诺斯基

31
myfun(){
    [ -d "$1" ]
}
if myfun "path"; then
    echo yes
fi
# or
myfun "path" && echo yes

1
否定呢?
einpoklum

怎么样,@ einpoklum?
马克·里德

@MarkReed:我的意思是,在您的示例中添加“ else”案例。
einpoklum

myfun“路径” || echo no
Hrobky

13

仅使用选项-d检查目录时要小心!
如果变量$ 1为空,则检查仍将成功。可以肯定的是,还要检查变量是否为空。

#! /bin/bash

is_directory(){

    if [[ -d $1 ]] && [[ -n $1 ]] ; then
        return 0
    else
        return 1
    fi

}


#Test
if is_directory $1 ; then
    echo "Directory exist"
else
    echo "Directory does not exist!" 
fi

1
我不确定这如何回答所问的问题。虽然很高兴知道空的$ 1可以在为空时返回true,但它并不能提供任何有关如何从bash函数返回true或false的见解。我建议创建一个新问题“对空的shell变量进行测试会怎样?” 然后将其发布为答案。
DRaehal 2014年

3
请注意,如果您在$1"$1")处添加了正确的引号,则无需检查是否为空变量。这[[ -d "$1" ]]将失败,因为这""不是目录。
紧急情况'16

3

我遇到了一个绊脚石(尚未明确提及?)。也就是说,不是怎么返回布尔值,而是如何正确地对它求值!

我想说if [ myfunc ]; then ...,但这是完全错误的。请勿使用括号!if myfunc; then ...是这样做的方法。

截至@Bruno和其他重申,true并且false命令,不重视!这对于理解shell脚本中的布尔值非常重要。

在这篇文章中,我使用布尔变量进行了解释和演示:https : //stackoverflow.com/a/55174008/3220983。我强烈建议您检查一下,因为它是如此紧密相关。

在这里,我将提供一些返回和评估的示例从函数布尔值的:

这个:

test(){ false; }                                               
if test; then echo "it is"; fi                                 

不产生回声输出。(即false 返回假)

test(){ true; }                                                
if test; then echo "it is"; fi                                 

产生:

it is                                                        

(即true 返回 true)

test(){ x=1; }                                                
if test; then echo "it is"; fi                                 

产生:

it is                                                                           

因为0(即true)是隐式返回的。

现在,这就是让我烦恼的原因...

test(){ true; }                                                
if [ test ]; then echo "it is"; fi                             

产生:

it is                                                                           

test(){ false; }                                                
if [ test ]; then echo "it is"; fi                             

还生产:

it is                                                                           

使用括号在这里产生误报!(我推断“外部”命令的结果为0。)

我的文章的主要收获是:不要像使用典型的相等性检查那样使用方括号来评估布尔函数(或变量)if [ x -eq 1 ]; then...


2

紧接在之前使用truefalse命令return,然后不return带任何参数。该return会自动使用你的最后一个命令的值。

return如果不使用1或0 ,则提供的参数不一致,特定于类型且容易出错。并且如先前的注释所述,使用1或0并不是实现此功能的正确方法。

#!/bin/bash

function test_for_cat {
    if [ $1 = "cat" ];
    then
        true
        return
    else
        false
        return
    fi
}

for i in cat hat;
do
    echo "${i}:"
    if test_for_cat "${i}";
    then
        echo "- True"
    else
        echo "- False"
    fi
done

输出:

$ bash bash_return.sh

cat:
- True
hat:
- False

1

如果将其重写function myfun(){ ... return 0; else return 1; fi;}为this ,则可能会起作用 function myfun(){ ... return; else false; fi;}。就是说,如果这是false函数中的最后一条指令,则整个函数将得到错误结果,但return无论如何都会中断函数并返回真实结果。我相信至少对于我的bash解释器来说是正确的。



1

出于代码可读性的原因,我相信返回true / false应该:

  • 在一条线上
  • 成为一个命令
  • 容易记住
  • 先提及关键字,return然后再提及另一个关键字(truefalse

我的解决方案是return $(true)return $(false)如下所示:

is_directory()
{
    if [ -d "${1}" ]; then
        return $(true)
    else
        return $(false)
    fi
}

0

紧跟@Bruno Bronosky和@mrteatime,我建议您只将布尔返回值写为“ backwards”。这就是我的意思:

foo()
{
    if [ "$1" == "bar" ]; then
        true; return
    else
        false; return
    fi;
}

这消除了每个return语句的难看的两行要求。

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.