56

Let's take a simple for loop

#!/bin/bash

for i in `seq 1 10`;
do
    echo $i
done

AFAIK semicolon in bash scripts makes shell execute current command synchronously and then go to the next one. Pressing enter does literally the same except it doesn't allow you to enter the following command, flushing the buffer immediately.

So why shell can't interpret the following line

for i in `seq 1 10`; do; echo $i; done

how does this for loop actually work?

3 Answers 3

66

The syntax of a for loop from the bash manual page is

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

The semicolons may be replaced with carriage returns, as noted elsewhere in the bash manual page: "A sequence of one or more newlines may appear in a list instead of a semicolon to delimit commands."

However, the reverse is not true; you cannot arbitrarily replace newlines with semicolons. Your multiline script can be converted to a single line as long as you observe the above syntax rules and do not insert an extra semicolon after the do:

for i in `seq 1 10`; do echo $i; done
6
  • 2
    The final script is wrong, as @dr01 pointed out, you need to remove the semicolon after do.
    – Jake
    Mar 17, 2018 at 19:45
  • 3
    @jake, this also says you must remove the semicolon after do. In addition, this answer explains why you must remove the semicolon after `do'. Mar 17, 2018 at 21:31
  • What if $i needs to be part of a file name? Does it need double quotes? Nov 7, 2018 at 21:41
  • 1
    do filename_${i} then
    – dopexxx
    Feb 10, 2020 at 15:50
  • @user4556274 according to the syntax "for i do; done" should work as well. why doesn't it?
    – Lavya
    Apr 17, 2020 at 6:33
31

The semicolon after do is an error and should not be there.

The following works correctly:

for i in `seq 1 10`; do echo $i; done 
0

Try it:

> for name in {Regular,Italic,Bold-Italic}; do echo $name;done
Regular
Italic
Bold-Italic

The element {1,2,3} is called brace expansion. Basically your shell expands this element and uses each produced entry into the for loop (see here for more info about brace expansion). If you don't use {}, the shell will understand 1,2,3 as a single element, and would get through in the loop only once, producing

❯ for name in Regular,Italic,Bold-Italic; do echo $name;done
Regular,Italic,Bold-Italic

which is not what you are probably expecting...

Alternatively, you can also use brace expansion to create a sequence using the following notation

❯ for i in {1..5}; do echo $i; done
1
2
3
4
5

It is worth to mention that you can create different strings with a sequence pattern using brace expansion and use it into the for loop, as shown here:

❯ for i in A{1..5}BC; do echo $i; done
A1BC
A2BC
A3BC
A4BC
A5BC
4
  • 1
    Note that the brace expansion in the first example is not needed (could have used a simple whitespace-delimited list) and that the brace expansion in the third example is not a brace expansion at all in bash (that loop iterates over the single string {A1..A5}). The answer also does not address the actual issue in the question (there's an error in the code).
    – Kusalananda
    Apr 21 at 14:27
  • @Kusalananda How does this not address the actual question if I showed how to iterate through a loop in the shell? About using space instead braces in the first example, you are right, the braces are optional. About calling {A1..A5} brace expansion, I think your statement is wrong, William Shoots mention that "The brace expression itself may contain either a comma-separated list of strings or a range of integers or single characters.". So {A1..A5} is called brace expansion, indeed. Apr 21 at 14:58
  • 1
    The question is, "So why shell can't interpret the following line" (followed by shell code containing a syntax error). One could answer that question and then possibly add more info about brace expansions. {A1..A5} is not a brace expansion because there is no sequence of letters or numbers filling the range between the two strings A1 and A5 (try, e.g. echo {A1..A5} as opposed to echo {1..5}).
    – Kusalananda
    Apr 21 at 15:03
  • You are right, my answer was wrong, now I fixed it. Thank you for your explanation. Yes, my answer does diverge a bit from the actual answer... Apr 21 at 15:09

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.