在 Bash 中对反引号的求值

在 Bash 中对反引号的求值

我对 Bash 中反引号的求值感到困惑。我以前见过这样的代码,它很有意义:

RESULT=`whoami`

这会将命令的输出存储whoamiRESULT变量中,并确认反引号的计算结果为输出其中的命令。但我还看到过类似下面的代码:

if `wget google.com -T 2 -t 1 -o /dev/null`; then 
   echo "Internet ok"
fi

这是通过尝试获取 google 主页来测试互联网连接(使用 进行-t 1一次尝试,使用-T 2进行 2 秒超时,并重定向到,/dev/null因为它实际上并不想要输出,而只是想看看它是否成功)。代码读起来好像作者期望反引号会评估命令的退出代码wget而不是输出。

但它确实有效。它打印Internet ok是否可以连接到 google.com,如果我将 URL 更改为不存在的无意义 URL,它就不满足 if 语句并且不打印任何内容。我不明白为什么这会起作用。

独立运行wget具有有效和无效 URL 的命令在两种情况下都不会打印任何内容,只是退出代码有所不同。

我的结论是,有一个特殊的构造用于if后跟反引号,它返回退出代码而不是输出。我错了吗?

答案1

不,反引号没有特殊含义,您甚至可以wget在语句中不使用反引号来运行命令if
if始终评估所跟随命令的退出代码。

可以找到更全面的概述这里


编辑

反引号启动在子 shell 中执行的命令替换并返回退出代码。if它只检查返回代码,而不使用命令的输出。

要比较命令的输出,您可以使用[,它必须以 结尾],这基本上是一个测试。测试可以是任何东西

  • man test
  • 字符串比较

    [ "hello" == "test" ]
    
  • 整数测试

    [ 2 -eq 3 ]  
    

如果测试成功,您将获得退出代码 0(true),否则不为 0(false),再次由 进行评估if

因此,您心中应该有如下想法。

if [ "`wget google.com -T 2 -t 1 -o /dev/null`" == "" ]
then 
    echo "emptY"
fi

但这没有多大意义,因为将输出重定向到/dev/null您将始终从[ "wget google.com -T 2 -t 1 -o /dev/null获得 true " == "" ]
另一方面,检查wget命令的输出是否包含输出(忽略)也没有用-o /dev/null,因为即使在错误情况下您也会得到输出,但返回代码不同。

答案2

在 bash if shell 脚本中,现在避免使用反引号,而使用命令替换$(...)语法。

它比非常模糊的反引号更清晰,并且支持嵌套,这是反引号无法实现的。例如:

command $(command two $(command three))

答案3

我终于通过讨论主题在bash邮件列表中。结论如下:

  • 这里的语句没有什么特别之处if,它只是执行后面的命令if,然后根据该命令的退出代码进行分支。这里的意外行为归因于命令替换本身。
  • 反引号命令(命令替换)始终计算为输出其中的命令,而不是退出代码(这不是什么新东西,只是确认是否使用反引号if是无关紧要的)。
  • 基于以上两点,基于以下因素if `cmd` ...运行身体的不明显原因if退出代码cmd cmd不向 stdout 写入任何内容关于 shell 命令执行,有一个 POSIX 规范规则,其内容如下:

如果没有命令名称,但命令包含命令替换,则命令应以最后执行的命令替换的退出状态完成。否则,命令应以零退出状态完成。

參考文獻:http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

  • 所以,这只是因为在没有向标准输出写入任何内容的情况下cmd,shell - 而不是执行一个空命令 - 采用命令替换的退出代码(cmd其自身的退出代码)并将其作为父命令的退出代码返回 - 然后冒泡到if

为了更好地说明这一点,请参见以下示例:

$ `true`
$ echo $?
0
$ `false`
$ echo $?
1

shell 首先运行true,它不会向 stdout 发出任何内容,因此生成的命令为空。根据上述规则,我原本预计空命令要么确定地成功,要么确定地失败,但它以退出代码true而不是“空命令的退出代码”完成。

相关内容