views:

66

answers:

4

I am writing a simple unix shell script:

#!/bin/bash                                                                  

# abort the script if a command fails
set -e

# abort the script if an unitialized shell variable is used
set -u

i = 0;
while [$i -l 1]
do
  src/meshpro input/martini.off video/noise/image$i.off -noise $i
  src/meshview video/noise/image$i.off -output_image video/noise/image$i.jpg -exit_immediately
  i='expr $i + 0.1'
done

When I try to run the script, I get the following error: line 14: i: command not found. I used a tutorial to apply to my code. Any suggestions on what I'm doing wrong?

+2  A: 

Do not put spaces around the equal sign, and you don't need the semicolon:

i=0

Also, you have quite a few other errors in the script.

Ignacio Vazquez-Abrams
am I allowed to increment by something other than an integer value, like I'm doing with my variable i?
Myx
Yes, but not with `expr`. Try `bc` instead.
Ignacio Vazquez-Abrams
thanks =) I tried bc (i='bc $i + 0.01'), but I get a line 10: [: too many argumentserror at the second run of the while loop.
Myx
Yes, because 1) you're performing command substitution incorrectly, and 2) you're not quoting properly.
Ignacio Vazquez-Abrams
+1  A: 

Spaces hurts. Put

i=0;

not

i = 0;

With spaces i is interpreted as command, not as assignement.

Enrico Carlesso
There are other spacing problems in the code - and the semicolon is not necessary.
Jonathan Leffler
Not necessary is different from wrong, and one error at time :)
Enrico Carlesso
+2  A: 

If using normal assignment, no spaces are allowed so you need:

i=0

(note that the semicolon is unnecessary). If you really want nicely formatted expressions, you can use the:

((i = 0))

statement. I would also use it in place of expr as well since expr is an external command with all the cost of process creation (this usually doesn't matter for quick and dirty scripts where only a few external processes are created but, if you find it happening a lot, you can get a very decent performance improvement).

Unfortunately, it doesn't like floating point but you can easily emulate it in your case since your numbers simply range from 0.0 through 0.9 (i.e., only the fractional part changes):

((i = i + 1))

and running it from 0 to 9, modifying the other lines to suit the new range.

The only other thing I'd check would be:

while [$i -l 1]

I think [ is treated as a command so you may need spaces (and you definitely need a real comparison operator):

while [ $i -lt 1 ]

And [ is typically also an external program, I prefer the bash built in [[.

Tying all those elements together:

#!/bin/bash                                                                  
set -e
set -u

((i = 0))
while [[ $i -lt 10 ]] ; do
    src/meshpro input/martini.off video/noise/image0.$i.off -noise 0.$i
    src/meshview video/noise/image$i.off -output_image \
        video/noise/image0.$i.jpg -exit_immediately
    ((i = i + 1))
done

You'll notice a difference with the output in that previously your zero file would have been image0.off with the others image0.X.off, whereas now it's image0.0.off. I think that's beneficial as well since it gives all your files exactly the same format.

If you disagree, it would be a simple matter to add:

mv video/noise/image0.0.jpg video/noise/image0.jpg

to the end of your script.

paxdiablo
re: [ vs [[ and [ being a command: style-wise, I really prefer using 'test' to '['. No one will ever make the mistake of writing 'while test$i -lt 1', but 'while [$i -lt 1]' seems to be an oft repeated mistake. Side note: both [ and test have been bash builtins for a long time now.
William Pursell
A: 

the expr is wrong. AFAIK it doesn't handle decimal. And i = 0 is wrong as well. no space around = sign.

#!/bin/bash                                                                  
set -e
set -u
i=0;
while true
do
  src/meshpro input/martini.off video/noise/image$i.off -noise $i
  src/meshview video/noise/image$i.off -output_image video/noise/image$i.jpg -exit_immediately
  i=$(echo "scale=2;$i + 0.1"|bc)
  case $i in 1.*) break ; esac
done
ghostdog74