What does "esac" mean at the end of a bash case statement? Is it required?
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
.
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. :-)