0

I am trying to read a file in bash forloop. But I do not know how to put write the script for this.

for i in $( seq 0 $step 10 )
do
    echo "Rendering: "$(( i + j ))
    python auto_fine.py density000000.vtu velocity000000.vtu $(( i + j ))
done

each and every loop I need to call

i -> 0 python auto_fine.py density000000.vtu velocity000000.vtu

i -> 1 python auto_fine.py density000010.vtu velocity000010.vtu

i -> 2 python auto_fine.py density000020.vtu velocity000020.vtu

Mathi
  • 45
  • 2
  • 9

3 Answers3

2

It seems to me that you need to zero pad the numbers sed provides to you:

As seen in How to zero pad a sequence of integers in bash so that all have the same width?, you need to do something like

$ seq -f "%06g" 0 10 100

Which returns:

000000
000010
000020
...
000100

All together,

for i in $(seq -f "%06g" 0 10 100)
do
    # echo "Rendering: "$(( i + j )) -- not sure what this does
    python auto_fine.py density$i.vtu velocity$i.vtu
done
Community
  • 1
  • 1
fedorqui
  • 275,237
  • 103
  • 548
  • 598
  • `/usr/bin/seq` is an external binary, but `printf` is a built-in. Why not use `printf`? – ghoti Jan 22 '16 at 12:52
  • @ghoti you mean something like `for i in printf "%06g " {1..10}`? It sounds like a very good idea. – fedorqui Jan 22 '16 at 12:55
  • I am getting error like this: [bash: 000008: value too great for base (error token is "000008")] – Mathi Jan 22 '16 at 12:58
  • @Mathi this is very strange and it is due to you trying to perform some arithmetic operation with the values. You can use the approach described in http://stackoverflow.com/a/24777667/1983854 to solve it. That is, to specify it is a value in the decimal base. – fedorqui Jan 22 '16 at 13:02
  • 1
    Almost that, yes. `for i in $(printf "%05d0 " {1..10}); do` is the approach in [my answer](http://stackoverflow.com/a/34947319/1072112). Apparently, bash is smart enough not to run a subshell that only executes a built-in. Yay bash! – ghoti Jan 22 '16 at 13:04
1

Bash can do this without requiring external tools like seq.

for i in {0..100}; do
  [[ $i = *0 ]] || continue
  python auto_fine.py density$(printf '%06d' $i).vtu velocity$(printf '%06d' $i).vtu
done

This uses pattern matching (*0) to limit your list to every 10 numbers, which is a bit of a hack, but will work against your sample data.

You could alternately loop against your zero-padded numeric strings directly:

for i in $(printf '%05d0 ' {0..10}); do
  python auto_fine.py density$i.vtu velocity$i.vtu
done

This option shows you every 10 items by placing a zero in the printf format after the incrementing number, which becomes the tens digit. If you want more arbitrary sequencing, you might use multipliers, still without spawning external processes:

low=0
high=100
mult=10

for i in $(eval echo {$low..$((high/mult))}); do
  n=$(printf '%06d' $((i*mult)))
  python auto_fine.py density$n.vtu velocity$n.vtu
done

Note the eval, which lets you expand variables for use in your sequence expression. (If you are getting these numbers from an external source, have your script validate them before using them!)

If you're using bash version 4 (i.e. not the native version on OSX), you also have increments available in sequence expressions. From the man page:

A sequence expression takes the form {x..y[..incr]}, where x and y are either integers or single characters, and incr, an optional increment, is an integer.

So perhaps:

low=0
high=100
mult=10

for i in $(eval "printf '%06d ' {$low..$high..$mult}"); do
  python auto_fine.py density$i.vtu velocity$i.vtu
done

Note that in sequence expressions, the first member of the sequence is the first number provided, rather than merely a product of a multiplier. We have quotes around the printf to ensure that the sequence expression is expanded by eval, and not interpreted by the command substitution ($(..)).

ghoti
  • 45,319
  • 8
  • 65
  • 104
  • Good one. Note, though, that the OP may need `seq` because it allows you to specify the steps and, even more important, use variables. – fedorqui Jan 22 '16 at 13:07
  • @fedorqui - thanks. In the first example, we sequence by 10's by skipping numbers that don't end in a 0. In the second, we implicitly inc by 10 because of the printf format string. In the third, we use the multiplier to create a *real* increment on our sequence expression. – ghoti Jan 22 '16 at 13:37
  • @fedorqui - and of course, I realized that I was testing in OSX only after this answer was written. The `{x..y..incr}` notation was introduced with bash 4, and handles sequences nicely. – ghoti Jan 22 '16 at 14:16
  • I don't see how these hacky solutions are superior to just using seq. The difference in performace is going to be negligible if there is any at all. All you are doing is hurting readability and making it less secure by using eval. – 123 Jan 22 '16 at 14:26
  • @123 - `seq` is not available in every operating system in which `bash` runs, and I always aim to provide answers that are portable. `seq` was only ported to FreeBSD as of version 9.0 (and I have a couple of boxes older than that), and it's also not in older Solaris boxes. Sure, it could be installed, but that certainly shouldn't be a requirement for an answer to be valid. As for `eval`, sure it's easy to misuse, but if you use it properly and do input validation, it doesn't need to be any less secure than other options. – ghoti Jan 22 '16 at 17:33
-1

looping for all the files in the current dir is trivial:

for i in $( ls -1 )
do
    # your code here, variable is referenced with $i
done

what's the j variable you are using?

godzillante
  • 1,174
  • 1
  • 17
  • 32