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. :-)

Tags:

Case

Bash