Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is "if [[ ... ]] then" (with no semicolon or newline) valid in ksh but not bash?

Tags:

bash

shell

ksh

I noticed a difference between KSH and Bash, and I'm looking for where this is documented, or perhaps a confirmation that one or the other is a bug.

In Korn Shell (seen on KSH88 and KSH93), this command works fine, and the result "yes" is printed:

if [[ -z "" ]] then echo yes ; fi       # Note no ';' after the ']]'

In Bash, I get a syntax error near unexpected token 'then'.

This behavior is only if I use the double brackets. If I use the single-bracketed form of conditional expression, both KSH and Bash give me a syntax error without the semicolon, but complain about the fi instead of the then.

Is this a bug or a feature? In ksh or Bash? I note that the man pages for Bash and ksh have a slightly different syntax for if, but that difference doesn't seem to apply to this case.


Edit: Someone (@jp48) pointed out what would be a significant difference in the syntax definition between the bash and the ksh man pages. However, looking at the Solaris (11.3) man page, which matches the AST source code, the syntax is:

if list ;then list [ ;elif list ;then list ] ... [ ;else list ] ;fi

The difference between that and the Bash man page is the placement (not the presence) of the semicolons before the elif/else/fi rather than after the list:

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

The alternate syntax without the semicolons comes from a public domain version of ksh (possibly PDksh), not the "official" ksh release.

like image 742
Menachem Avatar asked Mar 08 '23 05:03

Menachem


2 Answers

TL;DR: not a bug, according to ksh man page.


A main the difference between [ and [[ is that [ is a keyword and [[ is a builtin in both shells. Note that the "fallback exectuable" /bin/[ (which is essentially /bin/test) is never used for performance reasons, but what follows is better understood if we pretend this command were executed.

It is then noteworthy that ]] is also a keyword but ] is just a parameter passed to [/test.

Here is some proof (almost same output in both shells):

$ type [[
[[ is a shell keyword
$ type ]]
]] is a shell keyword
$ type [
[ is a shell builtin
$ type ]
***: not found

Having explained this let's see what happens in your example.

bash is behaving as expected according to this man page (i.e. it requires the ;):

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

Let's then focus on ksh, for reference I'll use FreeBSD's man page.

The syntax of if in ksh is as follows

if list then list [elif list then list] ... [else list] fi

And a list in ksh:

must end with a semicolon, a newline or a (syntactically correct) reserved word

And so [...] without ; is not a valid list (remember that the last ] is NOT a keyword nor builtin, but a "parameter" passed to [).

Whereas [[...]] is a valid list because ]] is a syntactically correct reserved word.

In conclusion, it is not a bug as it obeys the spec; of course it is not best practice not to use the ; (or newline) and probably not POSIX compliant.

like image 75
jp48 Avatar answered Mar 09 '23 19:03

jp48


Well, they're not actually the same shell so you can't call it a bug if they react differently :-)

For bash, it's plainly spelt out in the man page, there's most definitely a semicolon before the then:

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

There's also a similar line in my ksh man page so, if I was forced to pick out one for misbehaving, it would be ksh. But I haven't done a deep dive into it to see if there's some other option which may affect this. A cursory glance just states (for both) that newlines may substitute for the semicolon.

But, bottom line, if you follow the syntax as described, you shouldn't have any issues.

like image 26
paxdiablo Avatar answered Mar 09 '23 18:03

paxdiablo