This is a Bash question about renaming / incrementing file names with a series of 'for' loops. I don't understand the behavior...

Working with the ImageMagick convert command

If I do this with say, 3 source files:

$ convert *.miff dir/%d.miff
$ convert *.miff dir1/%d.miff

I get the expected behavior, with dir and dir1 both containing the files 0.miff 1.miff 2.miff - this is the required behavior. However convert reads all the source images into memory and soaks up resources (Try this with 30 - 40 large image files), not necessarily in strict file order.

This is better, file by file, in strict order, to satisfy the end processing requirement, one file at a time

$ for var in `ls -v *.miff`; do convert $var dir/%d.miff; done
$ for var in `ls -v *.miff`; do convert $var dir1/%d.miff; done

But, I get 0.miff 1.miff 2.miff in dir and 3.miff 4.miff 5.miff in dir1

I have tried assigning different variables to *.miff and $var for each loop and using variations on %d.miff such as $((x++)).miff. No change - incrementing continues upwards instead of resetting to '0' at each 'for' loop.

I have searched for a meaningful answer but suspect this is a behavior embedded in bash and appears to be related to the use of the $var variable.


The question is simplified to avoid overwhelming the reader but there are 4 loops, each doing different things, culminating in recombination of the images created in the 4 directories; as follows with the modified script, per Jesse_p's answer:

for i in `ls -v *.miff`; do 
  convert "$i" -depth $depth -roll +0+0 -sample 50% B/"$((x++)).miff"

for i in `ls -v *.miff`; do 
  convert "$i" -depth $depth -roll +0+1 -sample 50% G/"$((x++)).miff"

for i in `ls -v *.miff`; do
  convert "$i" -depth $depth -roll +1+0 -sample 50% g/"$((x++)).miff"

for i in `ls -v *.miff`; do 
  convert "$i" -depth $depth -roll +1+1 -sample 50% R/"$((x++)).miff"

for ((R=0,G=0,g=0,B=0;R<=101;R+=1,G+=1,g+=1,B+=1)); do
  convert R/$R.miff G/$G.miff B/$B.miff depth $depth \
     -colorspace sRGB -combine "$((x++))_$name.tiff"    
  • 3
    As far as I can tell, that for f in files..; convert $f dir/%d.jpg; done just creates 0.jpg on every run, overwriting the previous ones. Not 0, 1, 2 etc, and definitely not using the numbers of files in another directory. So, can you show what you really tried to do? – ilkkachu Jul 21 '18 at 22:31
  • I have simplified the code in the question. The image files in each dir are shifted in the x, y axis, using the -roll option. Then the images from each folder are recombined - superpixel demosaic process - there are 4 directores - one for each channel (RGGB). This didn't seem relevant to the question... – George Cheshire Jul 21 '18 at 22:46
  • @GeorgeCheshire, You say that you "suspect this is a behavior embedded in bash and appears to be related to the use of the $var variable", and seem to ask for help on that, but you're not showing what it is you're actually asking Bash to do. That makes it rather difficult to tell why it doesn't work, and what you should change. – ilkkachu Jul 21 '18 at 23:11
  • For me, it was a difficult question to ask - just how much information to include, without overwhelming the reader. I noticed $var changed the behaviour of the sequence of loops, as opposed to using a glob. I thought that was explained in the body of the question. But thank you and I will reread and edit where necessary - thanks for pointing this out. – George Cheshire Jul 21 '18 at 23:32
  • Reflecting on your comment I see that 'x' in $((x++)) = '0' in the first instance, incrementing through 4 loops. If I have this right, a glob redefines the same file set each time it is invoked - hence x=0 in the first instance every time. Where a bunch of files are assigned a variable, the incremented value of x carries through to the next loop and increments further. However, regardless of the variable assigned to the files throughout the 4 loops 'x' is still incremented and must therefore be set x=0 prior to each sequential loop. – George Cheshire Jul 22 '18 at 5:55

According to the ImageMagick documentation you can use -scene to set the starting sequence number. (V6.2 and above):

That being said, as ilkkachu points out and my tests have confirmed, your loops will just continuously overwrite a file called 0.miff and not increment at all. You could create incrementing files with the following:

for file in *.miff; do convert "$file" "dir/$((x++)).miff"; done
for file in *.miff; do convert "$file" "dir1/$((x++)).miff"; done

x=0 assigns the value of 0 to the variable named x.

$((x++)) will increment the value of x after the current operation. So on run one it will be 0.miff, then 1.miff, etc. We call x=0 again between loops to ensure we start back at 0 on the next run.

note it's better to glob files (*.miff) than to parse ls

  • 1
    @Jesse_b, ls -v can be useful if the filenames have numbers without leading zeroes. It sorts 1, 2, 10 correctly, while the default sort order used by the glob probably doesn't. Though of course there are the usual whitespace and glob character issues, but if that's not a problem ls -v might be the easiest way to get the sorting right... – ilkkachu Jul 21 '18 at 23:25
  • The image sequence is critical for this application as the image channels need to be shifted and then recombined for the same source image. – George Cheshire Jul 21 '18 at 23:46
  • x=0 - obviously - too close to the problem... thanks again – George Cheshire Jul 22 '18 at 0:06

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.