false; echo $?
上面将输出1
,这与我所知道的所有其他编程语言相矛盾。
有什么原因吗?
false
不是布尔值,就像其他编程语言一样。这只是位于/bin/false
(/usr/bin/false
在Mac上)的程序,旨在始终返回错误退出代码1 true
。因此,这里没有铸造这样的事情。这与退出代码有关。
if myprog; then echo OK; fi
变得简单而直观。否则,您将不得不颠倒每项测试才能使程序成功!
false; echo $?
上面将输出1
,这与我所知道的所有其他编程语言相矛盾。
有什么原因吗?
false
不是布尔值,就像其他编程语言一样。这只是位于/bin/false
(/usr/bin/false
在Mac上)的程序,旨在始终返回错误退出代码1 true
。因此,这里没有铸造这样的事情。这与退出代码有关。
if myprog; then echo OK; fi
变得简单而直观。否则,您将不得不颠倒每项测试才能使程序成功!
Answers:
这是一个约定,但考虑到它特别有用。通常,如果程序成功,这就是您所需要知道的。但是,如果失败,则可能需要了解有关失败的各种信息,包括失败的原因,修复方法等。零均值表示“成功”,而零均值表示“零”则使您可以轻松地检查是否成功,并根据需要调查特定错误以获取更多详细信息。许多API和框架都有类似的约定-成功的函数返回0,而失败的函数返回描述特定失败情况的错误代码。
xargs
使用在127左右范围内的不同错误代码来指示一组命令如何失败。可以完成的转换是将int转换为bool,其中0映射为成功(我想您希望将其表示为true / 1;但是要意识到这只是另一个任意约定),而所有其他值都将失败。
Bash是一种编程(脚本)语言,但它还是一种外壳程序和一个用户界面。如果0
是错误,则程序只能出现一种错误。
但是在Bash中,任何非零值都是错误,我们可以使用1-255之间的任何数字来表示错误。这意味着我们可以有很多不同类型的错误。1
是一个一般错误,126
表示无法执行文件,127
表示“未找到命令”,等等。这是带有特殊含义的Bash 退出代码列表,其中显示了一些最常见的退出代码。
成功也有很多种(退出状态为0
)。但是,成功可以使您继续进行下一步-您可以将结果打印到屏幕上或执行命令等。
/usr/include/sysexits.h
注释出口值可能更理想,即使它们代表的约定可以追溯到1980年代。该约定超出bash的范围。
0
是错误,则程序只能出现一种错误”。该声明是关键,也是为什么该答案应该放在首位的原因。
这里有两个相关的问题。
首先,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
mkdir deleteme && cd _$ && pwd
就不会真正失败。但我们必须通过替换它mkdir deleteme || cd _$ || pwd
,这在我看来是远远不太清楚,因为我们真正想要做的是什么mkdir deleteme
“ 和 ” cd _$
“ 和 ” pwd
...(用“和”具有在这里从日常语言它的意义)。
&&
运算||
符代替运算符是不够的。您将需要完全应用戴摩根定律。请参阅:en.wikipedia.org/wiki/De_Morgan%27s_laws
true
对应于零和false
对应于非零的状态是很自然的。首先,如果我告诉你一些事情,“告诉你真相”取决于我所说谎的谎言的数量:要么是零,我已经(整体上)告诉了事实,要么是非零,我撒了谎。这本质上是相同的,就是希望逻辑and
与通用的加法“和”相对应(显然,当限制为自然数时)。
true
与的所有其他值关联起来更为方便false
。(这基本上与对程序返回值的考虑相同)。
true
行为就像乘法1和false
-1。以-1的幂表示,这意味着它们的true
行为分别为“偶数”和false
“奇数”。再次,这是true
值得为零...
我发现重要的一个基本点就是要理解这一点。通常,在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
按照惯例,退出代码为0表示成功。 在几乎每个现代系统上,EXIT_SUCCESS均为 0。
编辑:
“为什么测试0和测试1都返回0(成功)?”
这是一个完全不同的问题。答案是,传递单个参数进行测试始终会成功,除非该参数是空字符串(“”)。请参阅开放组文档。
test 0
和test 1
返回0(成功)?
test
不测试数值。它测试该字符串是否为空字符串。 man test
想要查询更多的信息。
AFAIK这来自C约定,如果成功,则应返回0。看到:
man close
大多数C(POSIX)API都是这样构建的。 http://en.wikipedia.org/wiki/C_POSIX_library
这是一个可以追溯到Unix早期的惯例。
按照惯例,如果成功,所有系统调用都将返回0,否则返回非零,因为这样可以使用不同的数字来指示不同的失败原因。
外壳程序遵循此约定,0表示最后一个命令成功,否则为非零。同样,对于输出错误消息,非零返回值也很方便:例如1:“脑死亡”,2:“无情”,依此类推。
您试图将对/错与成功/失败等同起来。
它们是两个完全不同的二分法,尽管起初有些微妙!
在shell脚本中,没有true / false这样的东西。Shell的“表达式”不解释为true / false。相反,shell“表达式”是成功或失败的过程。
显然,一个过程可能由于许多原因而失败。因此,我们需要更大的设置代码来映射可能的故障。正整数可以解决问题。另一方面,如果该过程成功,则意味着它确实完成了应该执行的操作。由于只有一种方法可以执行此操作,因此我们只需要一个代码。0可以解决问题。
在C中,我们正在创建一个程序。在shell脚本中,我们正在运行一堆程序来完成某些工作。
区别!