50

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?

  • 2
    The index entry for esac points exactly where it should — to the line that defines it and illustrates that it's required. – hobbs Jan 19 '16 at 13:52
  • @hobbs, you are correct that the index points to the line that illustrates its use but it does not define it in any way, especially compared to the way it describes the use of other characters like "|" or ";" or ";;". Now that I've read the answer(s), the backwards spelling "case" appears to be such a de facto standard for ending commands that most experienced users would take it for granted. – GrnMtnBuckeye Jan 20 '16 at 15:31
  • If you didn't have esac or something like it, how do you think it would be able to tell where the end of the case statement is? – Barmar Jan 20 '16 at 20:36
  • It defines it as being part of the syntax of the case statement, in the same way that else, elif, and fi are defined as being part of the syntax of an if 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 a case statement, so it's where a case statement ends. The fact that it's case spelled backwards is a convenient curiosity, but the computer doesn't care, it just knows that it's looking for a certain word. – hobbs Jan 20 '16 at 20:37
  • 1
    @hobbs "...there isn't anything to say about it..." yet you just wrote a paragraph of explanation of why there's nothing to say about it. The important thing is to just understand the intent of the "esac". That's why this question has a straight answer with a fair number of upvotes. – Angelo Jun 7 '17 at 13:47
94

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.

  • 33
    You mean why isn't it od to end a do block? :) – Wildcard Jan 18 '16 at 22:37
  • 4
    Imagine having to type \od every time you wanted to use that utility! Which is rare, but my point stands ;) – Score_Under Jan 18 '16 at 23:20
  • 2
    Pulled you off of 666. You're welcome :P. And great answer! – TheWanderer Jan 19 '16 at 1:17
  • 12
    @Wildcard It's fi and not neht, so by analogy it would be rof (or elihw) and not od (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. – zwol Jan 19 '16 at 16:11
  • 1
    ROTFL nothing else to say – gerhard d. Jan 20 '16 at 15:50
53

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.

6

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

  • What's case out? never seen that syntax – Dani_l Jan 23 '16 at 6:04
  • 1
    @Dani_l That's Algol68 syntax not adopted by the bourne shell. – jlliagre Jan 23 '16 at 6:55
  • Why would they call it od even if it wasn't already taken? Wouldn't it be rof or elihw? – flarn2006 Aug 23 '18 at 18:32
  • Picking do ~ od, if ~ fi and case ~ 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. – NevilleDNZ Aug 25 '18 at 8:51
1

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
    Syntax came from Bourne, which again was inspired by ALGOL. – Runium Jan 18 '16 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.