$的含义?(美元问号)在shell脚本中


Answers:


212

这是最后执行的命令的退出状态。

例如,该命令true始终返回状态,0并且false始终返回状态1

true
echo $? # echoes 0
false
echo $? # echoes 1

从手册中:(可通过调用man bashshell来实现)

$?       扩展到最近执行的前台管道的退出状态。

按照惯例,退出状态0表示成功,非零返回状态表示失败。在Wikipedia上了解有关退出状态的 更多信息。

您可以在此在线手册上看到其他类似的特殊变量:https : //www.gnu.org/s/bash/manual/bash.html#Special-Parameters


注意$?是两个不同的参数,$?不会出现在bash(1)联机帮助页中。
乔什·哈布达斯

19

$?返回最后执行的命令的退出值。echo $?在控制台上打印该值。零表示成功执行,而非零值映射到各种失败原因。

因此,在编写脚本时;我倾向于使用以下语法

if [ $? -eq 0 ]; then
 # do something
else
 # do something else
fi

比较将在等于0或不等于上进行0

**根据注释进行更新:理想情况下,不应使用以上代码块进行比较,请参阅@tripleee注释和说明。


15
不,这是反模式。任何看起来像的东西都cmd; if [ $? -eq 0 ]; then应该重构为if cmd; then。非常目的if(并且在外壳的其他流程控制语句)是运行一个命令并检查其退出状态。
人间

if cmd;在某些情况下可能不是很可读,特别是在cmd引用另一个脚本时。
萨拉·阿里扬

1
现在,这甚至是错误的。[ 1 ]并且[ 0 ]都是真实的;[没有运算符的情况下,将检查参数是否为非空字符串。
Tripleee

2
我要去做vendor/bin/drush status bootstrap | grep -q $(vendor/bin/drush php-eval 'if (function_exists("t")) echo t("Successful");') &> /dev/null;。如果我不得不将其放在一行中,if [ ... ]那将是非常难以理解的。我计划将该行的输出存储到变量中,以便if [ $drupal_installed -eq 0 ]稍后再说。
第三者

1
@thirdender正确的解决方案是将复杂测试封装在shell函数中。
三人房

12

回声$?-给出最近执行的命令的退出状态。此退出状态很可能是一个数字,表示零,表示成功;任何非零值,表示失败

-这是bash中的一个特殊参数/变量。

$?-它给出了存储在变量“?”中的值。

BASH中一些类似的特殊参数是1,2,*,#(通常在echo命令中显示为$ 1,$ 2,$ *,$#等)。



5

最小POSIX C退出状态示例

要理解$?,您必须首先了解POSIX定义的进程退出状态的概念。在Linux中:

  • 当进程调用exit系统调用时,内核会存储传递给系统调用的值(int即使进程死亡也会)。

    退出系统调用由exit()ANSI C函数调用,而return从中调用则间接调用main

  • 经常使用fork+ 调用退出子进程(Bash)的进程exec可以通过wait系统调用检索子进程的退出状态

考虑一下Bash代码:

$ false
$ echo $?
1

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 “特殊参数”:

外壳专门处理几个参数。这些参数只能被引用;不允许分配给他们。[...]

?扩展到最近执行的前台管道的退出状态。

然后,ANSI C和POSIX建议:

  • 0 表示程序成功

  • 其他值:程序因某种原因失败。

    确切的值可以指示故障的类型。

    ANSI C没有定义任何变量的含义,并且POSIX指定的值大于125: “ 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 ]及其参数,另请参见:Bash中单方括号和双方括号之间的区别




2

输出最后执行的unix命令的结果

0 implies true
1 implies false
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.