9

I stumbled across this oddity and can't quite figure out why it works:

$ for ((i=0;i<8;i++)) {
>   printf '%d...' "$i";
> }; echo
0...1...2...3...4...5...6...7...

A for loop in bash using brace syntax? I can't reproduce this using a non-arithmetic for loop at all, and the manpage and help both seem to require the do:

$ help for
<SNIP>
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    Arithmetic for loop.

    Equivalent to
        (( EXP1 ))
        while (( EXP2 )); do
            COMMANDS
            (( EXP3 ))
        done

Hmm, so if I just…

$ ((i=0)); while ((i<8)) { printf '%d...' "$i"; ((i++)); }
-bash: syntax error near unexpected token `{'

Nope!

Is this braced for-loop syntax

  1. Documented anywhere (official?)
  2. A legitimate different way to represent an arithmetic for loop in Bash?
  3. Just something I'm missing about how a "normal" arithmetic for loop is interpreting the input?

P.S. – This was tested on OS X Mavericks with both a homebrew-installed Bash 4.2.45(2)-release as well as the vanilla 3.2.51(1)-release.

kojiro
  • 74,557
  • 19
  • 143
  • 201
  • AFAIK, it is a largely undocumented hack in Bash, probably needed for compatibility with the Bourne shell which also supported the brace notation, also undocumented. It is not peculiar to Mac OS X; it works like that on Ubuntu 12.04 too. It doesn't seem to work with `while` loops or `until` loops, though. – Jonathan Leffler Mar 24 '14 at 20:10
  • @JonathanLeffler How do you write an arithmetic `for` loop in Bourne shell syntax? The closest thing I have is `dash`, and I'm unable to find or guess the syntax. – kojiro Mar 24 '14 at 20:14
  • If you actually bothered to read the documentation that was posted in that answer that you simply downvoted out of hand, you would have read that both `{ }` and `do done` are both command grouping constructs. They're not generally interchangeable, but they are in the context of loops and if statements. – Sammitch Mar 24 '14 at 20:15
  • It is an optional way of writing the body of the `for` loop; the condition would be written differently in Bourne shell, but you could write things like `for i in 1 2 3; { echo $i; }` in Bourne shell, or use `do` in place of `{` and `done` in place of `}`. (I'd forgotten that it existed until your question reminded me of it; I've never used it seriously because it was not documented and hence not guaranteed to be supported.) – Jonathan Leffler Mar 24 '14 at 20:16
  • @Sammitch It's explicitly *not* a structure for grouping commands [according to POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html#tag_23_02_09_12). I would've happily reversed my downvote and even accepted the given answer if the poster had wanted to adjust it. – kojiro Mar 24 '14 at 20:22
  • @Sammitch: the now-deleted answer was not accurate. The `do...done` construct cannot be used where `{ ... }` can be used; you can only use `do ... done` after a `for`, `while` or `until` loop, whereas you can write `{ echo Hi; }` anywhere a command could appear (e.g. `if { echo Hi; }; then echo Lo; fi`. You can't do that with `do` and `done`. – Jonathan Leffler Mar 24 '14 at 20:23
  • Sigh. Now I have a (presumably) [retaliatory downvote](http://meta.stackexchange.com/questions/92942/retaliatory-downvoting). Is there some way I can improve the question? – kojiro Mar 24 '14 at 20:26
  • The question is fine. Sadly, there's not a lot you can do about a single down-vote. If you get a rash of down-votes, you can ask the moderators to investigate; or the automatic systems may spot the problem too. – Jonathan Leffler Mar 24 '14 at 20:35
  • ** This sort of undocumented hack is just [perfect for playing code-golf](http://codegolf.stackexchange.com/questions/tagged/code-golf) – Digital Trauma Mar 24 '14 at 21:19

1 Answers1

9

Transferring some comments into an answer:

AFAIK, it is a largely undocumented hack in Bash, probably needed for compatibility with the Bourne shell which also supported the brace notation, also undocumented. It is not peculiar to Mac OS X; it works like that on Ubuntu 12.04 too. It doesn't seem to work with while loops or until loops in Bash, though.

How do you write an arithmetic for loop in Bourne shell syntax?

It is an optional way of writing the body of the for loop; the condition would be written differently in Bourne shell, but you could write things like

for i in 1 2 3
{
    echo $i
}

in Bourne shell, or use do in place of { and done in place of }.

(I'd forgotten that it existed until your question reminded me of it; I've never used it seriously because it was not documented and hence not guaranteed to be supported.)

The do ... done construct cannot be used where { ... } can be used; you can only use do ... done after a for, while or until loop, whereas you can write { echo Hi; } anywhere a command could appear (e.g. if { echo Hi; }; then echo Lo; fi. You can't do that with do and done.

The best way to check the veracity of this answer is likely to be to download the Heirloom Bourne Shell from the Heirloom Project.


I've downloaded the source code for the Heirloom Bourne Shell (a CVS repository) and built it, and tested it. It does indeed accept the braces after the for loop, and refuses to recognize them as surrogates for do and done after an until or while loop.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278