为什么shell中的0为true,但false为1?


122
false; echo $?

上面将输出1,这与我所知道的所有其他编程语言相矛盾。

有什么原因吗?


3
它也与Unix方式保持一致...成功时不返回任何内容。
阿卜杜拉·吉巴利

21
因为退出状态不是布尔值。就那么简单。
詹斯2012年

2
请记住,这false不是布尔值,就像其他编程语言一样。这只是位于/bin/false/usr/bin/false在Mac上)的程序,旨在始终返回错误退出代码1 true。因此,这里没有铸造这样的事情。这与退出代码有关。
米哈伊尔·瓦辛

Shell是操作系统的(用户)界面。Unix等程序出于回答中给出的原因(能够通信多个失败原因)而遵循以0退出(OK)退出的惯例。外壳仅保留该约定,这使构造if myprog; then echo OK; fi变得简单而直观。否则,您将不得不颠倒每项测试才能使程序成功!
彼得-

Answers:


93

这是一个约定,但考虑到它特别有用。通常,如果程序成功,这就是您所需要知道的。但是,如果失败,则可能需要了解有关失败的各种信息,包括失败的原因,修复方法等。零均值表示“成功”,而零均值表示“零”则使您可以轻松地检查是否成功,并根据需要调查特定错误以获取更多详细信息。许多API和框架都有类似的约定-成功的函数返回0,而失败的函数返回描述特定失败情况的错误代码。


6
我理解这个答案,但是我仍然不明白为什么布尔值到int的转换是反向的。是否有一个“返回布尔约定”表示:如果返回true,则表示没有错误,如果返回false,则表示发生了错误(例如,众所周知的“整数=错误代码约定”)?
Guillaume86

1
假设从布尔值到int的转换意味着您并不真正理解答案。零表示成功,而1,2,...,255均为错误代码,可以有效地传达不同的失败情况。一个特定的示例xargs使用在127左右范围内的不同错误代码来指示一命令如何失败。可以完成的转换是将int转换为bool,其中0映射为成功(我想您希望将其表示为true / 1;但是要意识到这只是另一个任意约定),而所有其他值都将失败。
八点三人

79

Bash是一种编程(脚本)语言,但它还是一种外壳程序和一个用户界面。如果0是错误,则程序只能出现一种错误。

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

成功也有很多种(退出状态为0)。但是,成功可以使您继续进行下一步-您可以将结果打印到屏幕上或执行命令等。


8
这种务实的答案显示了各种返回码的有用性,胜于其他一些答案的讲道性。
javadba

1
只是为了好玩,我将指出那些/usr/include/sysexits.h注释出口值可能更理想,即使它们代表的约定可以追溯到1980年代。该约定超出bash的范围。
ghoti

2
一个伟大,简单而务实的解释。这需要在顶部。
雷伊·伦纳德·阿莫拉托

3
“如果0是错误,则程序只能出现一种错误”。该声明是关键,也是为什么该答案应该放在首位的原因。
rayryeng

1
@LuisLavaire这是未定义的行为。实际上,该数字往往会被截断;但是,如果运行时生成警告和/或只是崩溃,那肯定不是“更多错误”。OS仅为该信息保留了一个字节,并且尝试将一个以上的字节放入肯定存在错误。但是OS设计师可能在第一天就崩溃了,耸了耸肩,并决定他们能做的最好的事情就是截断价值并继续前进。
八点三人

30

这里有两个相关的问题。

首先,OP的问题,为什么shell中的0为true但false为1?第二,为什么应用程序成功返回0,失败返回非零?

要回答OP的问题,我们需要了解第二个问题。这篇文章的众多答案都描述了这是一个约定,并列出了该约定提供的一些好处。这些优点中的一些总结如下。

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

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

零与编码无关。

如果我们要在32位整数字中存储一个(1),则第一个问题将是“大端字还是小端字?”,然后是“组成一个小端字的字节多长时间?”。 ”,而零将始终看起来相同。

还需要期望某些人在某些时候将errno转换为char或short,甚至浮动。当char的长度不小于8位(UNIX支持7位ASCII char机器)时,(int)((char)ENOLCK)不是ENOLCK,而(int)((char)0)为0且与char的建筑细节。

一旦确定0将是成功的返回值,则可以将任何非零值用于失败。这使许多退出代码可以回答操作为何失败的问题。

为什么shell中的0为true,但false为1?

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

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

然后有必要将这些操作的退出状态解释为布尔值。将成功(0)退出状态映射为true,将任何非零/失败退出状态映射为false 是有意义的。这样做可以有条件地执行链接的Shell命令。

这是一个例子mkdir deleteme && cd $_ && pwd。因为外壳程序将0解释为true,所以此命令可以按预期方便地工作。如果外壳程序将0解释为false,则必须将每个操作的解释后的退出状态反转。

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


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

另请参阅《高级Bash脚本指南》中的附录E


2
您好,只需强调一下,如果shell将零解释为false,将非零解释为true,那么这样做的技巧mkdir deleteme && cd _$ && pwd就不会真正失败。但我们必须通过替换它mkdir deleteme || cd _$ || pwd,这在我看来是远远不太清楚,因为我们真正想要做的是什么mkdir deletemecd _$pwd...(用“和”具有在这里从日常语言它的意义)。
雷米·皮尔

1
我想我在回答中提到了这一点。但是要明确一点,当您反转逻辑时,仅用&&运算||符代替运算符是不够的。您将需要完全应用戴摩根定律。请参阅:en.wikipedia.org/wiki/De_Morgan%27s_laws
轴颈纪要

1
另一个考虑因素:我至少看到三个原因,通常来说,陈述true对应于零和false对应于非零的状态是很自然的。首先,如果我告诉你一些事情,“告诉你真相”取决于我所说谎的谎言的数量:要么是零,我已经(整体上)告诉了事实,要么是非零,我撒了谎。这本质上是相同的,就是希望逻辑and与通用的加法“和”相对应(显然,当限制为自然数时)。
雷米·皮尔

1
(从先前的评论继续)。第二个原因是,有一个真理,但有许多非真理。因此,将的唯一值true与的所有其他值关联起来更为方便false。(这基本上与对程序返回值的考虑相同)。
雷米Peyre

(从先前的评论继续)。第三个原因是“对A的真实”与“对A的真实”,“对A的虚假”与“对A的虚假”相同,等等。因此它的true行为就像乘法1和false-1。以-1的幂表示,这意味着它们的true行为分别为“偶数”和false“奇数”。再次,这是true值得为零...
雷米Peyre

17

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

test[ ][[ ]]运营商时,bash条件评估为真中的退出代码0(的/ bin中/真结果)的情况下。否则,它们的评估结果为假。

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

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

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

(( ))算术运算符解释1和0作为真假。但是,运营商不能作为一个完整的更换test[ ][[ ]]。这是显示算术运算符何时有用的示例:

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

感谢您对大括号对括号在true / false上的解释
javadba

15

按照惯例,退出代码为0表示成功。 在几乎每个现代系统上,EXIT_SUCCESS均为 0。

编辑:

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

这是一个完全不同的问题。答案是,传递单个参数进行测试始终会成功,除非该参数是空字符串(“”)。请参阅开放组文档


那么,为什么都test 0test 1返回0(成功)?
httpinterpret

5
@httpinterpret,test不测试数值。它测试该字符串是否为空字符串。 man test想要查询更多的信息。
卡尔·诺鲁姆

12

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


2
没有任何解释(或明显原因)的衰落投票毫无用处,而这样做的人则those脚,因为他们根本没有帮助社区。
阿卜杜拉·吉巴利

1
不原谅它……但这他们的2分……和@MichaelMrozek ..得分为19.6k,不会太糟,大声笑。
亚历克斯·格雷

1
@alexgray这是两年前;当时我大约有5k。而我更加好奇什么是错的答案比对代表
迈克尔Mrozek


4

这是一个可以追溯到Unix早期的惯例。

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

外壳程序遵循此约定,0表示最后一个命令成功,否则为非零。同样,对于输出错误消息,非零返回值也很方便:例如1:“脑死亡”,2:“无情”,依此类推。


这就是答案。
彼得-

3

您试图将对/错与成功/失败等同起来。

它们是两个完全不同的二分法,尽管起初有些微妙!

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

显然,一个过程可能由于许多原因而失败。因此,我们需要更大的设置代码来映射可能的故障。正整数可以解决问题。另一方面,如果该过程成功,则意味着它确实完成了应该执行的操作。由于只有一种方法可以执行此操作,因此我们只需要一个代码。0可以解决问题。

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

区别!


令人困惑。输入“ man [”。它显示了测试实用程序对表达式进行求值,如果求值为true,则返回零(true)退出状态;否则,返回0。否则返回1(假)。如果没有表达式,则test还返回1(假)。
cavalcade

1

记住它的一个好方法是:

  • 返回码回答“答案是什么?” 正确(或其他结果)或错误
  • 退出代码回答“出了什么问题?” 退出代码或没有问题(0)
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.