【问题标题】:Meaning of $? (dollar question mark) in shell scripts$的含义? (美元问号)在 shell 脚本中
【发布时间】:2011-11-07 01:29:26
【问题描述】:

是什么

echo $?

在shell编程中是什么意思?

【问题讨论】:

  • 上一个命令的退出状态

标签: shell scripting special-characters


【解决方案1】:

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

例如命令true总是返回0的状态,false总是返回1的状态:

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

来自手册:(可通过在您的 shell 中调用 man bash 访问)

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

按照惯例,退出状态0 表示成功,非零返回状态表示失败。了解更多关于退出状态on wikipedia

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

【讨论】:

  • 注意 $? 是两个不同的参数,$? 不会出现在 bash(1) 手册页中。
【解决方案2】:

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

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

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

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

** 更新基于评论:理想情况下,您不应该使用上面的代码块进行比较,参考@tripleee cmets 和解释。

【讨论】:

  • 不,这是一个反模式。任何看起来像cmd; if [ $? -eq 0 ]; then 的东西都应该重构为if cmd; thenif(以及 shell 中的其他流控制语句)的真正目的是运行命令并检查其退出状态。
  • if cmd; 在某些情况下可能不太可读,尤其是当 cmd 引用另一个脚本时。
  • 现在更不对了。 [ 1 ][ 0 ] 都是真的; [ 不带运算符检查参数是否为非空字符串。
  • 我即将做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 ]
  • @thirdender 解决这个问题的正确方法是将复杂的测试封装在一个 shell 函数中。
【解决方案3】:

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

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

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

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

【讨论】:

    【解决方案4】:

    它具有命令的最后状态码(退出值)。

    【讨论】:

      【解决方案5】:

      最小的 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 建议:

      • 0 表示程序成功

      • 其他值:程序以某种方式失败。

        确切的值可以指示失败的类型。

        ANSI C 没有定义任何值的含义,POSIX 指定大于 125 的值:What is the meaning of "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

      【解决方案6】:

      来自http://www.gnu.org/s/bash/manual/bash.html#Special-Parameters

      ?
      Expands to the exit status of the most recently executed foreground pipeline. 
      

      【讨论】:

        【解决方案7】:

        参见3.4.2 Special Parameters下的The Bash Manual

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

        有点难找,因为它没有被列为$?(变量名是“just”?)。当然,另请参阅exit status 部分;-)

        编码愉快。

        【讨论】:

          【解决方案8】:

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

          0 implies true
          1 implies false
          

          【讨论】:

            猜你喜欢
            • 2011-10-13
            • 2014-02-01
            • 2016-10-19
            • 2014-11-06
            • 1970-01-01
            • 2013-08-30
            • 2012-01-30
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多