6

I am trying to learn shell scripting, so I created a simple script with a loop that does nothing:

#!/bin/bash
names=(test test2 test3 test4)
for name in ${names[@]}
do
        #do something
done

however, when I run this script I get the following errors:

./test.sh: line 6: syntax error near unexpected token done'
./test.sh: line 6: done'

What have I missed here? are shell scripts 'tab sensitive'?

fenerlitk
  • 4,364
  • 9
  • 26
  • 37

6 Answers6

7

No, shell scripts are not tab sensitive (unless you do something really crazy, which you are not doing in this example).

You can't have an empty while do done block, (comments don't count) Try substituting echo $name instead

#!/bin/bash
names=(test test2 test3 test4)
for name in ${names[@]}
do
       printf "%s " $name
done
printf "\n"

output

test test2 test3 test4
shellter
  • 33,781
  • 7
  • 75
  • 89
  • thanks that works =), is there a way I can get all output in one line? – fenerlitk May 10 '12 at 13:03
  • 1
    note that `echo` is very handy to print line-by-line data as the original example showed. Learn about `printf` (search here on S.O. for examples) as it really powerful and flexible aid in formatting the printing of your data. Good luck. – shellter May 10 '12 at 13:14
  • 6
    A valid "no-op" command is [`:`](http://www.gnu.org/software/bash/manual/bashref.html#Bourne-Shell-Builtins) – glenn jackman May 10 '12 at 13:37
  • 1
    @glennjackman : yes, good point. As fenerlitk said 'I am trying to learn shell scripting', I figured it made sense that s/he would want to see the loop in action. Fenerlitk , note that the ':' no-op command could have been put in your loop, preceding you comment, i.e. `: # do something`, and that loop would have finished, but you wouldn't have seen anything happen. Good luck to all. – shellter May 10 '12 at 13:42
6

dash and bash are a bit brain-dead in this case, they do not allow an empty loop so you need to add a no op command to make this run, e.g. true or :. My tests suggest the : is a bit faster, although they should be the same, not sure why:

time (i=100000; while ((i--)); do :; done)

n average takes 0.262 seconds, while:

time (i=100000; while ((i--)); do true; done)

takes 0.293 seconds. Interestingly:

time (i=100000; while ((i--)); do builtin true; done)

takes 0.356 seconds.

All measurements are an average of 30 runs.

Thor
  • 39,032
  • 10
  • 106
  • 121
4

Bash has a built-in no-op, the colon (:), which is more lightweight than spawning another process to run true.

#!/bin/bash
names=(test test2 test3 test4)
for name in "${names[@]}"
do
    :
done

EDIT: William correctly points out that true is also a shell built-in, so take this answer as just another option FYI, not a better solution than using true.

chepner
  • 389,128
  • 51
  • 403
  • 529
  • 1
    : is the correct no-op, but 'true' has been a builtin for a long time. I imagine very few shells in use today would spawn a new process. – William Pursell May 10 '12 at 15:36
  • Bash `:` is like Python `pass` instruction – Stphane Nov 09 '17 at 17:18
  • Also to note (5 years later), `:` is *required* by POSIX to be a built-in, while `true` is only optionally (but I bet almost always) a built-in. – chepner Nov 09 '17 at 18:13
1

You could replace the nothing with 'true' instead.

Ja͢ck
  • 161,074
  • 33
  • 239
  • 294
1

You need to have something in your loop otherwise bash complains.

Douglas Leeder
  • 49,001
  • 8
  • 86
  • 133
1

This error is expected with some versions of bash where the script was edited on Windows and so the script actually looks as follows:

#!/bin/bash^M
names=(test test2 test3 test4)^M
for name in ${names[@]}^M
do^M
       printf "%s " $name^M
done^M
printf "\n"^M

where the ^M represents the carriage-return character (0x0D). This can easily be seen in vi by using the binary option as in:

vi -b script.sh

To remove those carriage-return characters simply use the vi command:

1,$s/^M//

(note that the ^M above is a single carriage-return character, to enter it in the editor use sequence Control-V Control-M)

Dror Harari
  • 2,597
  • 2
  • 23
  • 22