从Bash函数返回布尔值

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

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

然后我这样使用它:

if myfun filename.txt; then ...

当然这行不通。如何才能做到这一点呢?

288216 次浏览

用0表示真,用1表示假。

示例:

#!/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" ]
}
myfun(){
[ -d "$1" ]
}
if myfun "path"; then
echo yes
fi
# or
myfun "path" && echo yes
< p > 在只使用选项-d检查目录时要小心! < br > 如果变量$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
重写一下可能有用 function myfun(){ ... return 0; else return 1; fi;}作为这个function myfun(){ ... return; else false; fi;}。也就是说,如果false是函数中的最后一条指令,则整个函数的结果为假,但return无论如何都会以真结果中断函数。我相信至少对于我的bash解释器是这样的

为什么你要关心我说什么,尽管有350+个赞的答案

并不是0 = true1 = false。它是零表示没有失败(success)非零表示失败(N类型)

虽然选择答案在技术上是“真实的”;不要在的代码中放入return 1**。它会有一些不幸的副作用。

  1. 有经验的开发人员会把你当成业余爱好者(原因如下)。
  2. 有经验的开发人员不会这样做(原因如下)。
  3. 它很容易出错。
  • 即使是经验丰富的开发人员也会将0和1分别误认为是假的和真的(基于上述原因)。
  1. 它需要(或会鼓励)无关紧要和荒谬的评论。
  2. 它实际上不如隐式返回状态有用。

学习一些bash

bash手册说(强调我的)

返回[n]

导致shell函数停止执行并将值n返回给调用者。如果n没有提供,返回值是函数中的最后执行命令的退出状态

因此,我们不必用0和1来表示真和假。事实上,他们这样做本质上是微不足道的知识,只对调试代码、面试问题和让新手感到惊讶有用。

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

我们这里有…

04行是一个显式的[-ish]返回true,因为&&的RHS只有在LHS为true时才会执行

09返回与行08状态匹配的true或false

13返回false,因为行12

(是的,这可以打高尔夫球,但整个例子是人为的。)

另一种常见模式

# 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变量是如何揭示$?的含义的。(当然你知道$?是什么意思,但总有一天比你更不了解的人会知道的。除非你的代码正在进行高频交易,表达爱意,设置变量。)但真正的教训是,“如果不退出状态”;或者反过来“如果退出状态”;可以大声读出来并解释它们的意思。然而,最后一个可能有点过于雄心勃勃,因为看到exit这个词可能会让你认为它正在退出脚本,而实际上它正在退出(...) 命令组子壳。


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

return之前使用truefalse命令,然后使用不带参数的return命令。return将自动使用上一个命令的值。

如果你没有使用1或0,为return提供参数是不一致的,类型特定的,容易出错。正如前面的注释所述,在这里使用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

我遇到了一个问题(没有明确提到吗?)也就是说,不是如何返回布尔值,而是如何正确地求值!

我试图说if [ myfunc ]; then ...,但这是完全错误的。你不能使用括号!if myfunc; then ...是这样做的。

正如@Bruno和其他人重申的那样,truefalse命令,而不是值!这对于理解shell脚本中的布尔值非常重要。

在这篇文章中,我解释并演示了使用布尔变量: https://stackoverflow.com/a/55174008/3220983。我强烈建议你去核实一下,因为它们是如此密切相关。

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

这样的:

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

不产生回声输出。(即false 返回 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

此处使用括号生成假阳性!(我推断“outer”命令的结果是0。)

我的文章中主要的内容是:不要像典型的相等性检查(如if [ x -eq 1 ]; then... !)那样使用括号来计算布尔函数(或变量)!

继@Bruno Bronosky和@mrteatime之后,我建议你只写布尔返回“向后”。我的意思是:

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

这样就消除了每个return语句都需要两行代码的丑陋要求。

我发现测试函数输出的最短形式是简单的

do_something() {
[[ -e $1 ]] # e.g. test file exists
}


do_something "myfile.txt" || { echo "File doesn't exist!"; exit 1; }

出于代码可读性的考虑,我认为返回true/false应该:

  • 在一条线上
  • 成为一个命令
  • 容易记住
  • 在关键字return后面加上另一个关键字(truefalse)

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

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

下面是一些测试用例的好例子。

对于基本函数,在方法的最后一行调用true/false,或使用true; return提前退出。

function is_true() { true; }


if is_true; then echo 'true is true'; fi
if ! is_true; then exit; else echo '! true is ! true'; fi


function is_false() { false; }


if ! is_false; then echo 'false is false'; fi
if is_false; then exit; else echo '! false is ! false'; fi

如果不能立即返回,则将返回值存储在变量中。在设置变量时使用(true; echo $?)。这也适用于嵌套函数(见下一节)。

function from_var() {
local input=$1
local my_var
if ((input == 1)); then
my_var=$(true; echo $?)
else
my_var=$(false; echo $?)
fi
echo 'ignore this line'
(exit $my_var)
}


if from_var 1; then echo "return true is true"; else exit; fi
if from_var 0; then exit; else echo "return false is false"; fi

如果需要存储返回bool类型的函数调用的结果,可以使用相同的技术,但是将调用的输出通过管道传输到/dev/null,或者结果也可能包含来自echo或其他命令的字符串。注意if语句中的(exit $rval)可以让你正确地解释返回值。(其他方法如if (($rval))if [ $rval ]将不能正常工作。

# Return a truthy result
rval=$(from_var 1 >/dev/null; echo $?)
if (exit $rval); then echo "return true as variable is true"; else exit; fi


# Return a falsy result
rval=$(from_var 0 >/dev/null; echo $?)
if (exit $rval); then exit; else echo "return false as variable is false"; fi

这段代码的完整输出是:

true is true
! true is ! true
false is false
! false is ! false
ignore this line
return true is true
ignore this line
return false is false
return true as variable is true
return false as variable is false

如果不想使用> /dev/null抑制函数内部的输出,则重写以首先调用该函数。

from_var 0; rval="$?"