Why 0 is true but false is 1 in the shell?

false; echo $?

The above will output 1, which is contradictory with all other programming languages I know.

Any reason in this?

94253 次浏览

这只是一个约定,一个0退出代码意味着成功。几乎所有现代系统的 EXIT _ SUCCESS都将为0。

编辑:

“为什么测试0和测试1都返回0(成功) ?”

那是完全不同的问题。答案是,将单个参数传递给 test 总会导致成功,除非该参数是空字符串(“”)。看看 Open Group 文档

通常程序成功返回零,失败返回非零; false返回1是因为它是一个方便的非零值,但通常任何非零值都意味着某种程度的失败,许多程序将返回不同的非零值来指示不同的失败模式

这是一种惯例,但仔细想想就会发现它特别有用。一般来说,如果一个程序成功了,这就是你需要知道的全部。但是,如果失败了,您可能需要了解关于失败的各种信息——为什么会发生失败,如何修复失败等等。有零意味着“成功”和非零意味着失败,让你可以很容易地检查成功,并调查特定的错误,以获得更多的细节,如果你想。很多 API 和框架都有类似的约定——函数如果成功返回0,那么失败的函数就会返回一个描述特定失败情况的错误代码。

Bash 是一种编程(脚本)语言,但它也是一种 shell 和用户界面。如果 0是错误的,那么程序只能显示一种错误。

但是在 Bash 中,任何非零值都是错误,我们可以使用1到255之间的任何数字来表示错误。这意味着我们可以有许多不同类型的错误。1是一个常见错误,126表示文件无法执行,127表示“命令未找到”,等等。下面是 Bash有特殊含义的出口密码的列表,显示了一些最常见的退出代码。

还有很多种成功方式(退出状态为 0)。然而,一个成功将允许您继续进行下一个步骤 & mash; 您可以将结果打印到屏幕上,或者执行命令,等等。

AFAIK 这来自于 C 约定,如果成功的话你应该返回0。 参见:

man close

大多数 C (POSIX) api 都是这样构建的。 Http://en.wikipedia.org/wiki/c_posix_library

我发现一个重要的基本点是要理解这一点。通常在 bash 和 unix shell 中,返回值不是布尔值。它们是整数退出代码。因此,您必须根据惯例对它们进行评估,即0表示成功,而其他值表示一些错误。

对于 test[ ][[ ]]操作符,如果退出代码为0(结果为/bin/true) ,则 bash 条件的值为 true。否则它们的评估结果就是错误的。

字符串的计算方法与退出代码不同:

if [ 0 ] ; then echo not null ; fi
if [ $(echo 0) ] ; then echo not null ; fi


if [ -z "" ] ; then echo null ; fi

(( ))算术运算符将1和0解释为 true 和 false。但该操作符不能完全替代 test[ ][[ ]]。下面的例子说明了算术运算符何时有用:

for (( counter = 0 ; counter < 10 ; counter ++ )) ; do
if (( counter % 2 )) ; then echo "odd number $counter" ; fi
done

这里有两个相关的问题。

第一个问题是观察员的问题,为什么0是 true 而 false 在 shell 中是1?,第二个问题是 为什么应用程序成功时返回0,失败时返回非0?

为了回答 OP 的问题,我们需要理解第二个问题。对这篇文章的许多答复都说明这是一个公约,并列出了这个公约提供的一些细节。下面总结了其中的一些细节。

为什么应用程序成功时返回0,失败时返回非0?

调用操作的代码需要了解关于操作退出状态的两件事。如果操作没有成功退出 行动成功结束了吗?[ * 1] ,则可以使用任何值来表示成功。但是0比其他任何数字都更方便,因为它在平台之间是可移植的。2011年8月16日,总结 XIBO 对这个 有个问题的回答:

Zero 是独立于编码的。

如果我们想在一个32位整数字中存储一个(1) ,第一个问题应该是“ big-endian word 还是 little-endian word?”接下来是“组成一个小结尾单词的字节有多长?”而零永远看起来都是一样的。

同样需要预料到的是,有些人会在某些时候将 errno 转换为 char 或 short,甚至是 float。当 char 不是至少8位长(UNIX 支持7位 ASCII 字符机)时,(int)((char) ENOLCK)不是 ENOLCK,而(int)((char)0)与 char 的体系结构细节无关。

一旦确定0将是成功的返回值,那么对失败使用任何非零值都是有意义的。这允许许多 出口密码回答为什么操作失败的问题。

为什么0是 true 而 false 在 shell 中是1?

Shell 的一个基本用法是通过编写脚本实现流程的自动化。通常这意味着调用一个操作,然后根据操作的退出状态有条件地执行其他操作。菲利普 A。在他对这篇文章的回答中很好地解释了

通常在 bash 和 unix shell 中,返回值不是布尔值。 它们是整数退出代码。

然后有必要将这些操作的退出状态解释为一个布尔值。将成功(0)退出状态映射为 true,将任何非零/故障退出状态映射为 false 是有意义的。这样做允许条件执行链式 shell 命令。

这里是一个例子 mkdir deleteme && cd $_ && pwd。因为 shell 将0解释为 true,所以这个命令可以很方便地按预期工作。如果 shell 将0解释为 false,那么您必须为每个操作反转解释的退出状态。

简而言之,考虑到应用程序成功退出时返回0的约定,shell 将0解释为 false 是没有意义的。


[ * 1] : 是的,很多时候,操作需要返回的不仅仅是一个简单的成功消息,但这超出了这个线程的范围。

另请参阅高级 bash-Scripting 指南中的 附录 E

你试图把真/假等同于成功/失败。

它们是两个完全不同的二分法,虽然一开始很微妙!

在 shell 脚本中,没有 true/false 这种东西。Shell“表达式”不被解释为 true/false。相反,shell“表达式”是成功或失败的进程。

显然,流程可能由于许多原因而失败。因此,我们需要一个更大的集合代码来映射可能的故障。正整数起作用了。另一方面,如果进程成功了,那就意味着它完全做了它应该做的事情。因为只有一种方法可以做到这一点,我们只需要一个代码。0就行了。

在 C 语言中,我们正在创建一个程序。在 shell 脚本中,我们运行一系列程序来完成某些工作。

不一样!

这是一个可以追溯到 Unix 早期的会议。

按照惯例,如果成功,所有系统调用返回0,否则不返回0,因为这样可以使用不同的数字来指示不同的失败原因。

Shell 遵循这个约定,0表示最后一个命令成功,否则非0。类似地,非零返回值对于输出错误消息很有用: 例如1: “ brain dead”,2: “ hearless”,等等。

也许记住它的一个好方法是:

  • 返回代码回答“什么是答案?”真(或其他结果)或假
  • 退出代码回答“有什么问题?”退出代码或没有问题(0)

虽然这个问题没有被标记为 C 语言编程,而且大多数答案似乎间接地解释了真正的原因,但是我想我会回答,我希望一个 C 语言程序员会发现有用的东西。

恕我直言,歧义的真正来源是 C 标准。例如,在 C11草案规范(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)章节“7.22.4.4退出函数”与章节“7.18布尔类型和值 < stdbool.h >”中,EXIT _ SUCCESS 是零,这是从 linux shell cmdline 运行的程序在成功时期望返回的值,而 bool true 是非零(# Definition‘ ed to 1,但是称它为非零更安全。为什么?请参阅 https://stackoverflow.com/users/827263/keith-thompsonhttps://stackoverflow.com/a/40009047/4726668中的评论)。

引自 C11规范草案(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) :

7.22.4. 退出函数

最后,控制返回到主机环境。如果 status 的值为0或 EXIT _ SUCCESS,则返回状态成功终止的实现定义形式。如果 status 的值为 EXIT _ FAILURE,则返回一个实现定义的状态不成功终止形式。否则,返回的状态是实现定义的。

7.18 Boolean 类型和值 < stdbool.h >

3 其余三个宏适合在 # if 预处理指令中使用

没错

它展开为整数常数1,

假的

它展开为整数常量0,并且

_ _ bool _ true _ false _ are _ Definition

它展开为整数常量1。