命令的退出状态是由该命令还是执行该命令的shell进程?

Tim*_*Tim 3 bash command exit-status

来自 bash 手册

执行命令的退出状态waitpid系统调用或等效函数返回的值 。退出状态介于 0 和 255 之间,但如下所述,shell 可能会特别使用 125 以上的值。shell 内置命令和复合命令的退出状态也仅限于此范围。在某些情况下,外壳会使用特殊值来指示特定的故障模式。

  1. 什么决定了执行命令的退出状态,

    • 命令本身,即命令的执行确定退出状态,即确定执行命令的退出状态是命令的固有属性,就像解析命令执行的命令行参数是固有的命令,或
    • 执行命令的shell进程?上面提到
      waitpid系统调用在我看来是一个执行命令的退出状态是由shell进程实现的,而命令本身与一个执行本身的退出状态无关。
  2. 在bash进程中,我们什么时候可以获取执行命令的退出状态,

    • 仅当 bash 进程是交互式的,或者
    • 无论 bash 进程是交互式还是非交互式?当 bash 进程是非交互式的,我们如何检索在 bash 进程中执行的命令的退出状态?

Bru*_*ger 9

命令本身可以通过exit()系统调用的参数提供退出状态。shell(或其他程序,system()在 Perl 或 PHP 中如何?)可以通过wait()waitpid()系统调用获取子进程的退出状态。Unix/Linux/*BSD 内核都安排在子进程更改状态时将 SIGCHLD 传递给父进程。

但还有其他情况。通过 SIGKILL 终止的进程没有机会退出。exit()除非安装了 SIGSEGV 信号处理程序,否则取消引用无效地址的进程将没有机会调用。在这些情况下,内核会计算一个退出状态,其中包含一个表示“被信号杀死”的位,以及是什么信号导致进程被杀死。内核计算的退出状态被传递到被杀死进程的父进程。

  • `system()` 是使用 shell 执行的。“本地”方式是像`execve`这样的东西。 (2认同)

thr*_*rig 5

代码设置退出状态

$ perl -e 'END { $? = 42 }'; echo $?
42
$ 
Run Code Online (Sandbox Code Playgroud)

除非它不

$ perl -e 'sleep 999; END { $? = 42 }'
^C
$ echo $?
130
$ echo $((130-128))
2
$ kill -l | head -2
 1    HUP Hangup                        17   STOP Stopped (signal)         
 2    INT Interrupt                     18   TSTP Stopped
$ 
Run Code Online (Sandbox Code Playgroud)

或者做

$ perl -e '$SIG{INT}=sub{exit 7};sleep 999'                   
^C$ echo $?
7
$ 
Run Code Online (Sandbox Code Playgroud)

或者不应该有人变得活泼SIGKILL,等等。

否则,bash文档会产生误导,因为它waitpid设置了 16 位状态字,但bash仅传递了 shell 变量中的一个子集$?。如果 shell 用户试图将结果waitpid视为 8 位值(它不是),这可能会导致无知和混淆。

$ false; echo $?
1
$ perl -E 'system("false"); say $?'
256
$ perl -E 'system("false"); say $? >> 8'
1
$ 
Run Code Online (Sandbox Code Playgroud)