最小的 POSIX C 退出状态示例
要了解$?,您必须首先了解定义by POSIX 的进程退出状态的概念。在 Linux 中:
-
当进程调用exit 系统调用时,即使在进程终止后,内核也会存储传递给系统调用的值(int)。
退出系统调用由exit()ANSI C 函数调用,并且当您从main 执行return 时间接调用。
-
调用退出子进程(Bash)的进程,通常使用fork + exec,可以使用wait 系统调用检索子进程的退出状态
考虑一下 Bash 代码:
$ false
$ echo $?
1
C 的“等价物”是:
假.c
#include <stdlib.h> /* exit */
int main(void) {
exit(1);
}
bash.c
#include <unistd.h> /* execl */
#include <stdlib.h> /* fork */
#include <sys/wait.h> /* wait, WEXITSTATUS */
#include <stdio.h> /* printf */
int main(void) {
if (fork() == 0) {
/* Call false. */
execl("./false", "./false", (char *)NULL);
}
int status;
/* Wait for a child to finish. */
wait(&status);
/* Status encodes multiple fields,
* we need WEXITSTATUS to get the exit status:
* http://stackoverflow.com/questions/3659616/returning-exit-code-from-child
**/
printf("$? = %d\n", WEXITSTATUS(status));
}
编译运行:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o bash bash.c
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o false false.c
./bash
输出:
$? = 1
在 Bash 中,当您按 Enter 键时,会像上面一样发生 fork + exec + wait,然后 bash 将 $? 设置为分叉进程的退出状态。
注意:对于像 echo 这样的内置命令,不需要生成进程,Bash 只需将 $? 设置为 0 即可模拟外部进程。
标准和文档
POSIX 7 2.5.2“特殊参数”http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02:
?扩展到最近管道的十进制退出状态(请参阅管道)。
man bash“特殊参数”:
shell 专门处理几个参数。这些参数只能被引用;不允许分配给他们。 [...]
?扩展到最近执行的前台管道的退出状态。
ANSI C 和 POSIX 建议:
Bash 使用 if 的退出状态
在 Bash 中,我们经常使用退出状态$? 来隐式控制if 语句,如下所示:
if true; then
:
fi
true 是一个只返回 0 的程序。
以上等价于:
true
result=$?
if [ $result = 0 ]; then
:
fi
在:
if [ 1 = 1 ]; then
:
fi
[ 只是一个名称怪异的程序(以及行为类似的 Bash 内置程序),而 1 = 1 ] 它的参数,另请参阅:Difference between single and double square brackets in Bash