bash 为什么`if $(true) ; 那么... fi`成功了吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8965887/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 01:23:38  来源:igfitidea点击:

Why does `if $(true) ; then ... fi` succeed?

bashkshzshsh

提问by Keith Thompson

Inspired by this question:

受到这个问题的启发:

What should an if statement do when the condition is a command substitution where the command produces no output?

当条件是命令替换且命令不产生输出时,if 语句应该做什么?

NOTE:The example is if $(true); then ..., not if true ; then ...

注意:这个例子是if $(true); then ...,不是if true ; then ...

For example, given:

例如,给定:

if $(true) ; then echo yes ; else echo no ; fi

I would think that $(true)should be replaced by the output of the truecommand, which is nothing. It should then be equivalent to either this:

我认为$(true)应该用true命令的输出代替,这没什么。那么它应该等同于:

if "" ; then echo yes ; else echo no ; fi

which prints nobecause there is no command whose name is the empty string, or to this:

no之所以打印,是因为没有名称为空字符串的命令,或者如下:

if ; then echo yes ; else echo no ; fi

which is a syntax error.

这是一个语法错误。

But experiment shows that if the command produces no output, the ifstatement treats it as true or false depending on the status of the command, rather than its output.

但是实验表明,如果命令没有输出,则if语句根据命令的状态将其视为真或假,而不是其输出。

Here's a script that demonstrates the behavior:

这是一个演示行为的脚本:

#!/bin/bash

echo -n 'true:          ' ; if true          ; then echo yes ; else echo no ; fi
echo -n 'false:         ' ; if false         ; then echo yes ; else echo no ; fi
echo -n '$(echo true):  ' ; if $(echo true)  ; then echo yes ; else echo no ; fi
echo -n '$(echo false): ' ; if $(echo false) ; then echo yes ; else echo no ; fi
echo -n '$(true):       ' ; if $(true)       ; then echo yes ; else echo no ; fi
echo -n '$(false):      ' ; if $(false)      ; then echo yes ; else echo no ; fi
echo -n '"":            ' ; if ""            ; then echo yes ; else echo no ; fi
echo -n '(nothing):     ' ; if               ; then echo yes ; else echo no ; fi

and here's the output I get (Ubuntu 11.04, bash 4.2.8):

这是我得到的输出(Ubuntu 11.04,bash 4.2.8):

true:          yes
false:         no
$(echo true):  yes
$(echo false): no
$(true):       yes
$(false):      no
"":            ./foo.bash: line 9: : command not found
no
./foo.bash: line 10: syntax error near unexpected token `;'
./foo.bash: line 10: `echo -n '(nothing):     ' ; if               ; then echo yes ; else echo no ; fi'

The first four lines behave as I'd expect; the $(true)and $(false)lines are surprising.

前四行的行为符合我的预期;在$(true)$(false)线是令人惊讶的。

Further experiment (not shown here) indicates that if the command between $(and )produces output, its exit status doesn't affect the behavior of the if.

进一步的实验中(这里未示出)表明,如果之间的命令$()产生输出,它的退出状态并不影响的行为if

I see similar behavior (but different error messages in some cases) with bash, ksh, zsh, ash, and dash.

我看到类似的行为(但在某些情况下,不同的错误消息)bashkshzshash,和dash

I see nothing in the bash documentation, or in the POSIX "Shell Command Language" specification, to explain this.

我在 bash 文档或 POSIX“Shell 命令语言”规范中没有看到任何内容来解释这一点。

(Or perhaps I'm missing something obvious.)

(或者我可能遗漏了一些明显的东西。)

EDIT :In light of the accepted answer, here's another example of the behavior:

编辑:鉴于已接受的答案,这是行为的另一个示例:

command='' ; if $command ; then echo yes ; else echo no ; fi

or, equivalently:

或者,等效地:

command=   ; if $command ; then echo yes ; else echo no ; fi

采纳答案by William Pursell

See section 2.9.1 of the language spec. The last sentence of the first section reads:

请参阅语言规范的第 2.9.1 节。第一部分的最后一句话是:

If there is a command name, execution shall continue as described in Command Search and Execution . If there is no command name, but the command contained a command substitution, the command shall complete with the exit status of the last command substitution performed. Otherwise, the command shall complete with a zero exit status.

如果有命令名称,则应按照命令搜索和执行中的描述继续执行。如果没有命令名称,但命令包含命令替换,则该命令应以上次执行的命令替换的退出状态完成。否则,该命令将以零退出状态完成。

The $(true)is expanding to the empty string. The shell parses the empty string and finds that no command is given and follows the above rule.

$(true)扩大为空字符串。shell解析空字符串,发现没有给出命令,就遵循了上面的规则。

回答by Aaron McDaid

There are potentially twoexit codes to consider. First, here's another two experiments that should help:

可能有两个退出代码需要考虑。首先,这里有另外两个应该有帮助的实验:

# if $(echo true; false) ; then echo yes ; else echo no ; fi
yes

The inner commandexits with failure because of the false. But that's irrelevant because the output of the command is non-empty and hence the output ("true") is executed instead and its exit code takes priority.

所述内命令与由于故障退出false。但这无关紧要,因为命令的输出是非空的,因此会执行输出(“true”),并且其退出代码具有优先权。

# if $(echo false; true) ; then echo yes ; else echo no ; fi
no

Again, the command line inside the $( )is successful, but the output is no because the output ("false") takes priority.

再次,里面的命令行$( )是成功的,但是输出不是,因为输出(“false”)优先。

The exit status of the commands inside the $( )is relevant if and only ifthe output is empty or only whitespace. If the output is empty, there is no list of commands to execute and hence it appears that the shell will fall back on the exit status of the innercommand.

当且仅当输出为空或只有空格时,其中的命令的退出状态$( )才是相关的。如果输出为空,则没有要执行的命令列表,因此外壳似乎将退回到内部命令的退出状态。

回答by SiegeX

What appears to be happening is that bashkeeps the exit status of the last executed command

似乎正在发生的是bash保持上次执行命令的退出状态

This would explain why $(true)and $(false)have different behavior in an iftest. They both produce null commands which doesn't count as execution but they have different exit codes.

这将解释为什么$(true)$(false)if测试中具有不同的行为。它们都产生不计为执行的空命令,但它们具有不同的退出代码。

As soon as you use command substitution on a command that has output, $()attempts to execute that output as a command and the exit code of thatattempt is now the latest one used for the iftest

只要你有输出命令中使用命令替换,$()试图执行一个输出作为命令和退出代码尝试,现在使用的最新的一个if测试

回答by sarnold

What should an if statement do when the condition is a command substitution where the command produces no output?

当条件是命令替换且命令不产生输出时,if 语句应该做什么?

Output doesn't matter. What matters is the exit code:

输出无所谓。重要的是退出代码

   if list; then list; [ elif list; then list; ] ... [ else
   list; ] fi
          The if list is executed.  If its exit status is zero,
          the then list is executed.  Otherwise, each elif list
          is executed in turn, and if its exit status is zero,
          the corresponding then list is executed and the
          command completes.  Otherwise, the else list is
          executed, if present.  The exit status is the exit
          status of the last command executed, or zero if no
          condition tested true.

If you replace your $(echo true)and $(echo false)with something else you will probably see what is going on:

如果你用其他东西替换你的$(echo true)$(echo false),你可能会看到发生了什么:

$ if $(echo false) ; then echo yes ; else echo no ; fi
no
$ if $(echo command-does-not-exist) ; then echo yes ; else echo no ; fi
command-does-not-exist: command not found
no
$ 

The $(..)runs the command and then ifexecutes the results(in this case, just trueor falseor does-not-exist). An empty $()starts a subshell which successfully runs to completion and returns an exit code of 0:

$(..)运行命令,然后if执行该结果(在此情况下,只需truefalsedoes-not-exist)。一个空$()启动一个子shell,它成功运行到完成并返回一个退出代码0

$ if $() ; then echo yes ; else echo no ; fi
yes

Aaron raised some interesting points:

Aaron 提出了一些有趣的观点:

$ if $(echo true; false) ; then echo yes ; else echo no ; fi
yes
$ if $(echo 'true ; false') ; then echo yes ; else echo no ; fi
yes
$ if true ; false ; then echo yes ; else echo no ; fi
no

$ if $(echo false ; true) ; then echo yes ; else echo no ; fi
no
$ if $(echo 'false ; true') ; then echo yes ; else echo no ; fi
no
$ if false ; true ; then echo yes ; else echo no ; fi
yes
$ 

It appears that when executing a command constructed via the $()subshell, the first command's exit status is what matters.

似乎在执行通过$()子外壳构造的命令时,第一个命令的退出状态很重要。