title: Why are the bash -n and -z test operators not inverses for $@
body: <pre><code>function wtf() {
    echo "\$*='$*'"
    echo "\$@='$@'"
    echo "\$@='"$@"'"
    echo "\$@='""$@""'"
    if [ -n "$*" ]; then echo " [ -n \$* ]"; else echo "![ -n \$* ]"; fi
    if [ -z "$*" ]; then echo " [ -z \$* ]"; else echo "![ -z \$* ]"; fi
    if [ -n "$@" ]; then echo " [ -n \$@ ]"; else echo "![ -n \$@ ]"; fi
    if [ -z "$@" ]; then echo " [ -z \$@ ]"; else echo "![ -z \$@ ]"; fi
  }
  
  wtf
  </code></pre>
  
  <p>produces</p>
  
  <blockquote>
  <pre><code>$*=''
  $@=''
  $@=''
  $@=''
  ![ -n $* ]
   [ -z $* ]
   [ -n $@ ]
   [ -z $@ ]
  </code></pre>
  </blockquote>
  
  <p>though it seems to me that <code>[-n $@]</code> should be false because <a href="http://tldp.org/LDP/abs/html/comparison-ops.html" rel="noreferrer">7.3 Other Comparison Operators</a> indicates that <code>[ -n "$X" ]</code> should be the inverse of <code>[ -z "$X" ]</code> for all <code>$X</code>.</p>
  
  <blockquote>
    <h1><code>-z</code></h1>
    
    <p>string is null, that is, has zero length</p>
  
  <pre><code>String=''   # Zero-length ("null") string variable.
  
  if [ -z "$String" ]
  then
    echo "\$String is null."
  else
    echo "\$String is NOT null."
  fi     # $String is null.
  </code></pre>
    
    <h1><code>-n</code></h1>
    
    <p>string is not null.</p>
    
    <p>The <code>-n</code> test requires that the string be quoted within the test brackets. Using an unquoted string with <code>! -z</code>, or even just the unquoted string alone within test brackets (see Example 7-6) normally works, however, this is an unsafe practice. Always quote a tested string. [1]</p>
  </blockquote>
  
  <p>I know <code>$@</code> is special but I did not know it was special enough to violate boolean negation.  What is happening here?</p>
  
  <hr>
  
  <pre><code>$ bash -version | head -1
  GNU bash, version 4.2.42(2)-release (i386-apple-darwin12.2.0)
  </code></pre>
  
  <hr>
  
  <p>The actual numeric exit codes are all <code>1</code> or <code>0</code> as per</p>
  
  <pre><code>$ [ -n "$@" ]; echo "$?"
  0
  </code></pre>