Linux中退出代码的最小值和最大值是多少?


40

Linux中以下退出代码的最小值和最大值是什么:

  1. 从二进制可执行文件(例如:C程序)返回的退出代码。
  2. 从bash脚本返回的退出代码(调用时exit)。
  3. 从函数返回的退出代码(调用时return)。我认为这是介于0和之间255

对于第3部分,您是说要从Shell函数返回吗?这可能取决于外壳程序,但是我注意到Bash的手册说“ 退出状态介于0255之间 ”和“ 外壳程序内置程序和复合命令的退出状态也限制在此范围内。return当然是外壳程序内置程序。
Toby Speight,

相关(对大多数问题都有答案):进程终止时的默认退出代码?
斯特凡Chazelas

@TobySpeight,这是bash外壳程序的限制。其他一些shell zsh可以像这样返回任何带符号的32位值exit。有些人喜欢rces可以返回他们支持的任何类型的数据(标量或列表)。有关详细信息,请参见链接的问答。
斯特凡Chazelas

Answers:


74

传递给_exit()/ exit_group()系统调用的数字(有时称为退出代码,以避免与退出状态产生歧义,这也指的是退出代码或信号号的编码以及其他信息,具体取决于进程是被终止还是正常退出)是类型的int,因此在类似Unix的系统(例如Linux)上,通常是32位整数,其值从-2147483648(-2 31)到2147483647(2 31 -1)。

然而,在所有系统上,当父进程(或子subreaper或者init如果父去世)使用wait()waitpid()wait3()wait4()系统调用来检索它,只有它的低8位可(值从0到255(2 8 - 1))。

当使用waitid()API(或SIGCHLD上的信号处理程序)时,在大多数系统上(以及POSIX现在在该标准的2016版中更明确地要求(请参阅_exit()规范)),可以使用完整编号(在si_status返回结构的字段中) )。在Linux上不是这种情况,尽管它也会通过waitid()API 将数字截断为8位,但是将来可能会改变。

通常,您只想使用0(通常表示成功)到125,因为许多shell $?退出状态表示中使用大于128的值来编码被杀死进程的信号号,对于特殊情况则使用126和127。条件。

您可能希望使用126到255 exit()表示与外壳相同的含义$?(例如脚本执行时ret=$?; ...; exit "$ret")。使用0-> 255以外的值通常没有用。通常,仅当您知道父级将waitid()在不会截断的系统上使用API并且碰巧需要32位值范围时,才这样做。请注意,exit(2048)例如,如果您这样做,那么使用传统wait*()API的父母将认为这是成功的。

有关更多信息,请访问:

该问答将有望回答您的其他大多数问题,并阐明退出状态的含义。我还要添加一些内容:

除非进程被杀死或调用_exit()/ exit_group()系统调用,否则它无法终止。从main()in中返回时C,libc会使用返回值调用该系统调用。

大多数语言都有exit()包装该系统调用的函数,并且它们所取的值(如果有)通常按原样传递给系统调用。(请注意,这些通常会做更多的事情,例如由C的exit()函数完成的清理工作,这些函数会刷新stdio缓冲区,运行atexit()钩子...)

至少是这种情况:

$ strace -e exit_group awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group mawk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ strace -e exit_group busybox awk 'BEGIN{exit(1234)}'
exit_group(1234)                        = ?
$ echo | strace -e exit_group sed 'Q1234'
exit_group(1234)                        = ?
$ strace -e exit_group perl -e 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group python -c 'exit(1234)'
exit_group(1234)                        = ?
$ strace -e exit_group expect -c 'exit 1234'
exit_group(1234)                        = ?
$ strace -e exit_group php -r 'exit(1234);'
exit_group(1234)                        = ?
$ strace -e exit_group zsh -c 'exit 1234'
exit_group(1234)

当您使用0-255以外的值时,您偶尔会看到一些抱怨:

$ echo 'm4exit(1234)' | strace -e exit_group m4
m4:stdin:1: exit status out of range: `1234'
exit_group(1)                           = ?

当您使用负值时,一些shell会抱怨:

$ strace -e exit_group dash -c 'exit -1234'
dash: 1: exit: Illegal number: -1234
exit_group(2)                           = ?
$ strace -e exit_group yash -c 'exit -- -1234'
exit: `-1234' is not a valid integer
exit_group(2)                           = ?

如果传递给exit特殊内置函数的值在0-> 255之外,则POSIX会使行为未定义。

如果这样做,某些外壳会显示一些意外行为:

  • bashmksh但不是pdksh基于它)基于自身将值截断为8位:

    $ strace -e exit_group bash -c 'exit 1234'
    exit_group(210)                         = ?
    

    因此,在那些shell中,如果您确实想使用0-255之外的值退出,则必须执行以下操作:

    exec zsh -c 'exit -- -12345'
    exec perl -e 'exit(-12345)'
    

    那就是在同一过程中执行另一个命令,该命令可以使用所需的值调用系统调用。

  • 如在其他问答中所提到的,ksh93对于退出值从257到256 + max_signal_number而言,行为最奇怪exit_group()

    $ ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    zsh: suspended (signal)  ksh -c 'exit "$((256 + $(kill -l STOP)))"'
    

    否则将数字截断为bash/ mksh


¹不过,在下一个版本中,这种情况可能会改变。现在,ksh93AT&T已将开发工作作为社区的工作来接管,尽管POSIX以某种方式鼓励了该行为,


2
您知道是否有关于在si_statusLinux中实现完整退出代码的讨论吗?
罗斯兰

2
@Ruslan,不超过austingroupbugs.net/view.php?id=594#c1318(从埃里克·布莱克(红帽))在链路我给
斯特凡Chazelas

1
“是int类型,所以是32位整数”。Linux真的保证int永远是32bit吗?即使在某些微型微控制器上运行时?这让我感到非常奇怪。POSIX当然不是。
Voo

@Voo,那些微型微控制器无法运行Linux。尽管C要求int至少为16位,但是POSIX或多或少要求它至少为32位,并且编程环境必须具有uint32_t。我不知道Linux是否支持ints除了32bits之外的任何编程环境,我从来没有遇到过。
斯特凡Chazelas

1
在符合POSIX的操作系统上,您可以在最新版本的Bourne Shell中获得完整的32位退出代码,请参见:schillix.sourceforge.net/man/man1/bosh.1.html
大约

12

最小值为0,这被视为成功值。其他所有的都是失败的。最大值255也称为-1

这些规则适用于脚本和其他可执行文件以及外壳函数。

较大的值将得出256模。


2
确切地说,在某些类似Bourne的shell中(但不是bash或在其他最常用的exitshell中),传递给内置函数的退出代码不会被视为modulo-256,而是会导致错误。(例如,公用exit -1程序实际上不是exit 255大多数外壳程序中的便携式产品)。而无论是exit(-1)在C级相当于exit(255)是一个细节,那就是事实上的某些工作,但依赖于实现定义的行为(虽然这不是现代系统的一个问题,你很可能会利用在实践中)。
mtraceur

据我所知,只有ksh93将exit(1)参数限制为8位。
schily

6

这看起来很简单,但是麻烦了。

C语言(以及紧随其后的大多数其他语言,都是直接或间接的)要求从返回main等同于exit使用与返回值相同的参数进行调用。这是一个整数(返回类型非常清楚int),因此原则上范围是INT_MINto INT_MAX

但是,POSIX指出,只有传递给它的最低8位才exit可供等待的父进程使用,字面上就好像是“ status&0xFF”
因此,实际上,退出代码是一个(仍带符号的)整数,仅设置最低的8位。

因此,最小值将为-128,最大值为127。等一下,那是不对的。从0到255。

但是,a ,当然不能这么简单。实际上,Linux(或更确切地说是bash)的做法有所不同。返回码的有效范围是0到255(即无符号)。

为了避免混淆,为了安全起见,最好假设返回代码是未签名的,然后将所有返回的内容转换wait为未签名。这样,它便与您在Shell中看到的一致。由于清除了最高位(包括最高有效位),所以这甚至不是“错误的”,因为尽管经过了技术上的签名,但实际值始终是未签名的(因为从未设置过符号位)。
它还有助于避免将退出代码与进行比较的常见错误,即使程序退出时-1由于某种奇怪的原因,该错误也似乎不会出现-1(嗯,猜猜为什么!)。

关于最后一点,从函数返回,如果此函数恰好是main,则请参见上文。否则,它取决于函数的返回类型,原则上可以是任何值(包括void)。


在1989年waitid()推出之前,您一直是对的。
schily

@schily:不确定您的意思吗?waitid()只是做相同的事情,略有不同。它等待一个特定的id或任何线程,然后将结果写入指向的siginfo_t结构所在的si_status位置int(如此... signed,一样)。尽管如此,exit()只传递最低的8位,所以...完全相同。
戴蒙

exit()将参数的所有32位传递给内核,并waitid()从退出代码返回所有32位。也许您在Linux上检查了没有人愿意修复错误的地方。如果您不相信我,请在
符合

@schily:如果这是真的(我不认为是,但是无论如何),那么Linux就坏了。请阅读的链接到POSIX规范exit,特别是“说明”下的第二行,其中指出:“尽管只有最低有效的8位(即状态&0377)对等待的父进程可用。 “。符合标准的实现就是这样工作的-最低的8位而不是32位。您有传递32位的参考吗?
达蒙

我以为我提到Linux坏了。更糟糕的是:Linux内核人员拒绝修复错误。如果您阅读POSIX标准,则会发现1995版本(SUSv1)正确地解释了SVr4于1989年最初引入的功能,而该标准的最新版本(例如SUSv7tc2)甚至明确地解释了这一点,waitid()并且siginfo_t传递给SIGCHLD处理程序的结构返回exit()参数的所有32位。
schily

2
  1. 从二进制可执行文件(例如:C程序)返回的退出代码。
  2. 从bash脚本返回的退出代码(调用exit时)。

任何进程的退出码(无论是二进制可执行文件,shell脚本还是其他任何东西)的范围都在0到255之间。可以将一个较大的值传递给exit(),但是只有状态的低8位可用于通过其他过程wait()

  1. 从函数返回的退出代码(调用return时)。我认为这是介于0和255之间。

可以将AC函数声明为几乎返回任何类型。其返回值的限制是由类型完全取决于:例如,-128到127,用于一个函数返回signed char,或0至4.2十亿为一个函数返回unsigned int,或者任何浮点数至多并包括inf用于返回的功能double。这还不包括非数字类型,例如void *struct...

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.