title: Why does `if $(true) ; then ... fi` succeed?
body: <p>Inspired by <a href="https://stackoverflow.com/questions/8965509/why-if-ps-aux-grep-always-succeeds-in-bash">this question</a>:</p>
  
  <p>What should an if statement do when the condition is a command substitution where the command produces no output?</p>
  
  <p><strong>NOTE:</strong> The example is <code>if $(true); then ...</code>, not <code>if true ; then ...</code></p>
  
  <p>For example, given:</p>
  
  <pre><code>if $(true) ; then echo yes ; else echo no ; fi
  </code></pre>
  
  <p>I would think that <code>$(true)</code> should be replaced by the output of the <code>true</code> command, which is nothing.  It should then be equivalent to either this:</p>
  
  <pre><code>if "" ; then echo yes ; else echo no ; fi
  </code></pre>
  
  <p>which prints <code>no</code> because there is no command whose name is the empty string, or to this:</p>
  
  <pre><code>if ; then echo yes ; else echo no ; fi
  </code></pre>
  
  <p>which is a syntax error.</p>
  
  <p>But experiment shows that if the command produces no output, the <code>if</code> statement treats it as true or false depending on the status of the command, rather than its output.</p>
  
  <p>Here's a script that demonstrates the behavior:</p>
  
  <pre><code>#!/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
  </code></pre>
  
  <p>and here's the output I get (Ubuntu 11.04, bash 4.2.8):</p>
  
  <pre><code>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'
  </code></pre>
  
  <p>The first four lines behave as I'd expect; the <code>$(true)</code> and <code>$(false)</code> lines are surprising.</p>
  
  <p>Further experiment (not shown here) indicates that if the command between <code>$(</code> and <code>)</code> produces output, its exit status doesn't affect the behavior of the <code>if</code>.</p>
  
  <p>I see similar behavior (but different error messages in some cases) with <code>bash</code>, <code>ksh</code>, <code>zsh</code>, <code>ash</code>, and <code>dash</code>.</p>
  
  <p>I see nothing in the bash documentation, or in the POSIX "Shell Command Language" specification, to explain this.</p>
  
  <p>(Or perhaps I'm missing something obvious.)</p>
  
  <p><strong>EDIT :</strong> In light of the accepted answer, here's another example of the behavior:</p>
  
  <pre><code>command='' ; if $command ; then echo yes ; else echo no ; fi
  </code></pre>
  
  <p>or, equivalently:</p>
  
  <pre><code>command=   ; if $command ; then echo yes ; else echo no ; fi
  </code></pre>