Categories
bash

Oppa Semicolon Style

[No relation to that infuriatingly viral video.]

A recent Reddit thread about ffmpeg encoding somehow sidetracked into an unrelated discussion about semicolons. In the process of answering the questions therein, I suddenly realized that most bash newbies get confused about semicolons in scripts, and that there’s in fact a striking similarity between compound statements in bash and C.

First, a simple fact: Semicolons punctuate compound statements, and punctuation promotes proper parsing. Just look at the descriptions of compound statements in the bash man page:

case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac

if list; then list; [ elif list; then list; ] ... [ else list; ] fi

for name [ [ in [ word ... ] ] ; ] do list ; done

and think about how any program could be expected to assume that:

for i in 1 2 3 do echo do you do this $i time\? done

actually means:

for i in 1 2 3; do echo do you do this $i time\?; done

as opposed to the programmer having a complete brain-fart.

Now, you’re probably going: “Hang on, I don’t see anyone writing code all in a line like that!” That leads me to my next point: Semicolons can generally be replaced by newlines in compound statements. Hence, you’re far more likely to see this:

for i in 1 2 3; do
  echo $i
  echo breaker
done

or this:

for i in 1 2 3
do
  echo $i
  echo breaker
done

Notice that the first form simply substitutes a newline for the semicolon before done, and the second form also substitutes a newline for the semicolon before do. Both are functionally identical to each other and to the single-line (note the newline-semicolon substitution between the two echo statements as well):

for i in 1 2 3; do echo $i; echo breaker; done

as well as the odd duck:

for i in 1 2 3
do
          echo $i
  echo breaker; done

Don’t get crazy, though. The following is actually illegal in bash:

for i in 1
  2
     3
do
  echo $i; echo
    breaker; done

because it translates to the incorrect one-liner:

for i in 1; 2; 3; do echo $i; echo; breaker; done

“Wait a sec!” I hear you call, dear reader. “How about the double-semicolon in case clauses?”

Technically, bash treats this double-semicolon as a single token, so you can’t replace it with two newlines (or one, for that matter). You also can’t write:

case $i in
(1) echo yes ; ;
esac

That space between the two semicolons will cause bash to choke.


Now, if you’re a C programmer, you probably recognized the “shape” of the first two examples as being the equivalent of the indentation styles1 popularly known as K&R:

while (1) {
  do(something);
}

and Allman:

while (1)
{
  do(something);
}

I’ll therefore call the equivalents in bash K&R-style and Allman-style. Which one to use is purely a matter of preference; pick one and stick with it.

As for the all-in-one-liner, I’ll just call it No-style. You should avoid this style wherever possible, as it gets seriously unreadable very quickly. You’ll also regret it when you get hit by a dozen syntax errors on line 1; good luck trying to find them all.

And if you were working for me, and showed me that odd-duck code chunk…let’s just say you’d no longer be working for me. Call it NoJob-style.


  1. See Indentation Style – Wikipedia for more styles than you should ever care about. ↩︎

Leave a Reply

Your email address will not be published. Required fields are marked *