I have found multiple examples of "esac" appearing at the end of a bash case statement but I have not found any clear documentation on it's use. The man page uses it, and even has an index on the word (https://www.gnu.org/software/bash/manual/bashref.html#index-esac), but does not define it's use. Is it the required way to end a case statement, best practice, or pure technique?
4 Answers
Like fi
for if
and done
for for
, esac
is the required way to end a case
statement.
esac
is case
spelled backward, rather like fi
is if
spelled backward. I don't know why the token ending a for
block is not rof
.
-
48
-
5Imagine having to type
\od
every time you wanted to use that utility! Which is rare, but my point stands ;) Jan 18, 2016 at 23:20 -
the "for" is a loop it has to know when to stop, so they HAVE ta use the word done so it will stop looping, otherwise it won't? Jan 19, 2016 at 0:12
-
19@Wildcard It's
fi
and notneht
, so by analogy it would berof
(orelihw
) and notod
(also, of course,od
is already taken) ... but maybe this is expecting too much self-consistency out of one of the most self-inconsistent languages there is.– zwolJan 19, 2016 at 16:11 -
2It's
done
because the statement begins withdo
, notfor
orwhile
. Jan 19, 2016 at 19:17
The esac
keyword is indeed a required delimiter to end a case
statement in bash
and most shells used on Unix/Linux excluding the csh
family.
The original Bourne shell was created by Steve Bourne who previously worked on ALGOL68. This language invented this reversed word technique to delimit blocks.
case/esac
if/fi
do/od
The latter is no more do/od
but do/done
in Bourne and all the derived shells including bash
because od
was already existing as a Unix command since its inception (octal dump).
Note that do/done
functional blocks are introduced by either the for
, the while
, or the until
instructions. for
, while
and until
do not need to be terminated as done
is sufficient. That's the reason why there is no need for the hypothetical rof
and elihw
tokens.
The "esac
" terminates an earlier "case
" to form a "code-block".
In Algol68 they are used, generally the reversed character sequence of the introducing keyword is used for terminating the enclosure, e.g. ( if ~ then ~ else ~ fi, case ~ in ~ out ~ esac, for ~ while ~ do ~ od ).
I would call them "Guarded Blocks" after Edsger Dijkstra and his Guarded Command Language.
od
presumably was not used in the Bourne Shell because of the pre-existence of the Unix "od" command.
The history:
The "Guarded Block" idea appear to have come from ALGOL 68 e.g. English:
proc days in month = (int year, month)int:
case month in
31,
if year mod 4=0 ∧ year mod 100≠0 ∨ year mod 400=0 then 29 else 28 fi,
31, 30, 31, 30, 31, 31, 30, 31, 30, 31
esac;
The Soviet's Algol68 LGU implementation did the same: In English Algol68's reverent case statement reads case ~ in ~ out ~ esac
, in Cyrillic this reads выб ~ в ~ либо ~ быв
.
Then in 1975 Algol68's code-blocks were borrowed by Edsger Dijkstra for his Guarded Command Language. e.g.
if a ≥ b → max := a
| b ≥ a → max := b
fi
Presumably Dijstra used "Guarded Blocks" to overcome the Dangling else ambiguity implemented in Algol60 and then re-engineered in the C Programming Language. (cf. shift-reduce conflict.)
Finally - from Algol68 - "esac
" made it into the 1977 Bourne shell (where you discovered esac
) courtesy of Stephen R. Bourne who had developed an early Algol68 compiler called ALGOL 68C.
Famously Stephen also used these same Guarded Blocks in a "C header file" called macro.h
#define IF if(
#define THEN ){
#define ELSE } else {
#define ELIF } else if (
#define FI ;}
The notable software geniuses Landon Curt Noll and Larry Bassel stumbled upon Steve's macro.h code in 1984 while employed at National Semiconductor's Genix porting group and struggled to understand its application. And so Landon & Larry then created the International Obfuscated C Code Contest...
From 1984 until today there have been several thousand other "better" programming languages that do not use Dijkstra's Guarded Commands. And Steven Bourne's use of them in macro.h
is now often cited in the "Software Development Dissertations" of IT undergraduates as proof they were not sleep in lectures. :-)
-
-
1
-
Why would they call it
od
even if it wasn't already taken? Wouldn't it berof
orelihw
? Aug 23, 2018 at 18:32 -
Picking
do ~ od
,if ~ fi
andcase ~ esac
simply means that endless future generations of undergrads will be able to ponder Algol68 and add a simple "critique" of Algol68 into their final year project, without having to actually write more then a page (line?) of Algol68 code. Aug 25, 2018 at 8:51
Yes, it's required. As Jacob points out above, the logic of it is the same as if
/fi
. Traditional C comment delimiters /*
and */
also pair similarly. Because C was written so that Unix could be written mostly in C, with the minimum of assembly code, with a large overlap between the C and Unix development teams, it's reasonable to assume a common source of the notion that the closing equivalent of a multi-character block delimiter should be the same sequence of characters in reverse order.
In contrast, loops like for
, while
, and until
use do
...done
instead of reversing character order, so there is some inconsistency.
-
3
esac
points exactly where it should — to the line that defines it and illustrates that it's required.esac
or something like it, how do you think it would be able to tell where the end of thecase
statement is?case
statement, in the same way thatelse
,elif
, andfi
are defined as being part of the syntax of anif
statement. It doesn't have any semantics of its own, so there isn't anything to say about it, but it's at the end of the definition of acase
statement, so it's where acase
statement ends. The fact that it'scase
spelled backwards is a convenient curiosity, but the computer doesn't care, it just knows that it's looking for a certain word.