2

Continuing Semicolon in conditional structures (which handles single brackets), what's the point of having a semicolon after the closing DOUBLE bracket ]]?

In my tests, running

#!/bin/zsh -- if [[ "a" == "a" ]] then echo "true" else echo "false" fi if [[ "a" == "a" ]]; then echo "true" else echo "false" fi if [[ "a" == "a" ]] then echo "true" else echo "false" fi if [[ "a" == "a" ]]; then echo "true" else echo "false" fi 

yields

true true true true 

, and running

#!/bin/zsh -- if [[ "a" == "b" ]] then echo "true" else echo "false" fi if [[ "a" == "b" ]]; then echo "true" else echo "false" fi if [[ "a" == "b" ]] then echo "true" else echo "false" fi if [[ "a" == "b" ]]; then echo "true" else echo "false" fi 

yields

false false false false 

No error is reported. In zsh, what's the difference between the conditionals with a semicolon ; after the closing double bracket and the conditionals without a semicolon after the closing double bracket?

The same question goes for bash.

5
  • Yep, it works in this case, but not the way it's supposed to be ... Keywords like then must be at the beginning of a line or otherwise might be interpreted as a literal string ... Compare for example: if true then echo "true"; else echo "false"; fi to if true; then echo "true"; else echo "false"; fi Commented Jul 26 at 11:14
  • ... Probably worth noting as well that [[ is a keyword (try type [[) while [ is an alias for the command test so considered a command much like true in my example above. Commented Jul 26 at 11:52
  • @Raffa Thx for the example. In zsh, if true then echo "true"; else echo "false"; fi yields “zsh: parse error near `else'”. In bash, we get “bash: syntax error near unexpected token `else'”. That's confusing. What's the reason for the necessity of the semicolon here after true but not in the examples in the OP? Commented Jul 26 at 14:57
  • @user743115 I tried my best to explain what I think might help understand the difference in the answer below although I don't really consider it an answer ... But I hope it helps. Commented Jul 26 at 18:15
  • @user743115, true then echo "true" is as valid a regular command as echo if you do this, then that happens. Shell keywords are only recognized as such at the start of a command, so that's similar to if echo foo; else echo bar; fi. It's missing the mandatory then ... part, so a syntax error. But [[ .. ]] and (( .. )) and if ... fi and such are compound constructs where end is marked by the closing token. For regular (simple) commands, the semicolon (or newline) is needed to mark the end. Commented Jul 26 at 21:06

1 Answer 1

2

In bash and zsh [ is a builtin command where the ] is considered the last argument to that command and the shell parses what's in between in the way that you'd expect:

$ set -x $ if [ a = a ]; then echo "true"; else echo "false"; fi + '[' a = a ']' + echo true true 

... and in the Z shell:

% set -x % if [ a = a ]; then echo "true"; else echo "false"; fi +zsh:7> [ a '=' a ']' +zsh:7> echo true true 

The [[ on the other hand is a keyword (not a command) ... Furthermore what's in between [[ and ]] does not undergo similar normal parsing from the shell:

$ set -x $ if [[ a = a ]] then echo "true"; else echo "false"; fi + [[ a = a ]] + echo true true 

... and in the Z shell:

% set -x % if [[ a = a ]] then echo "true"; else echo "false"; fi +zsh:4> [[ a = a ]] +zsh:4> echo true true 

So, basically the returned status code is evaluated similar to [ but with different shell parsing.

Sort of like (but not really) this:

$ if (re () { return 2; }; re) then echo "true $?"; else echo "false $?"; fi false 2 

or this:

% if (true) then echo "true $?"; else echo "false $?"; fi true 0 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.