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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With