-1

I have some files named:

0001.jpg
0002.jpg
...
0050.jpg

I need to increment that number by 35, so that I obtain:

0036.jpg
0037.jpg
...
0085.jpg

I thought of trying the following:

for i in {0001..0050}; do
  mv -n $i $((i+35)) 
done

However I get the error bash: 0008: value too great for base (error token is "0008"). I'm not sure I understand what the base means here or how to get around it. I have seen this question. Although it explains the octal error, it is not immediately clear how it helps to iterate with a shifted index.

Massagran
  • 1,781
  • 1
  • 20
  • 29
  • 3
    Btw. I suggest to count from 0050 to 0001 because the ranges overlap. – Cyrus Sep 07 '19 at 18:04
  • Possible duplicate of [Value too great for base (error token is "08")](https://stackoverflow.com/q/24777597/608639), [Value too great for base (error token is “09”)](https://stackoverflow.com/q/21049822/608639), etc. – jww Sep 08 '19 at 00:40
  • @jww those two solutions are essentially "$((10#$hour + 1))", but, although hearing about octals numers was informative and interesting, it was not the solution I was looking for. – Massagran Sep 08 '19 at 20:13
  • @Massagran - Interesting, thanks. Why did you accept the answer that fixed your octal counting? – jww Sep 10 '19 at 14:06
  • @jww it was the first answer. – Massagran Sep 12 '19 at 21:24

4 Answers4

2

bash, like C, interprets a number that starts with a zero as an octal number when used inside an arithmetic expansion. This is the standard behavior for a POSIX sh. Since "8" is not a valid value inside an octal number, you get an error.

Since what you want is to count from 1 to 50 and add 35, and then format it as a number, you can do something like this:

#!/bin/sh

for i in $(seq 50 -1 1)
do
    mv -n $(printf '%04d.jpg' $i) $(printf '%04d.jpg' $((i + 35)))
done

This iterates from 50 to 1, and formats each number using the printf program. This is, incidentally, also portable POSIX sh in addition to working in bash.

bk2204
  • 64,793
  • 6
  • 84
  • 100
2

Eventually I went with:

for i in {50..1};
do
    old=$(printf '%04d.jpg' $i)
    new=$(printf '%04d.jpg' $((i + 34)))
    mv -i -- "$old" "$new"  #-i to avoid overwritting
done
Massagran
  • 1,781
  • 1
  • 20
  • 29
1

Problem is that bash arithmetic treats numbers starting with 0 as octal number and only 0-7 digits are allowed in octal system. You can prefix 10# before number to tell bash to accept given number as base 10 number and computer your sum.

You may use:

for i in {0010..0001}.jpg; do
   f="${i%.jpg}"
   echo mv "$i $(printf '%04d' $((10#$f + 10#35))).jog"
done

Once you're satisfied with output, remove echo before mv.

mv 0010.jpg 0045.jog
mv 0009.jpg 0044.jog
mv 0008.jpg 0043.jog
mv 0007.jpg 0042.jog
mv 0006.jpg 0041.jog
mv 0005.jpg 0040.jog
mv 0004.jpg 0039.jog
mv 0003.jpg 0038.jog
mv 0002.jpg 0037.jog
mv 0001.jpg 0036.jog
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 2
    Not sure if the first move should be from 0001.jpg to 0036.jpg because 0036.jpg will already exist. – Ray Toal Sep 07 '19 at 18:09
1

@Massagran almost your own solution:

#!/usr/bin/env bash
for i in {50..1}; do
  printf -v old_filename '%04d.jpg' $i
  printf -v new_filename '%04d.jpg' $((i + 35))
  [[ -f $old_filename ]] && mv --no-clobber -- "$old_filename" "$new_filename"
done

How it differs and improve your answer:

  • Rather than capturing the output of printf into a variable by running printf in a sub-shell, it uses the -v option, so printf outputs directly into the variable.

  • Before performing the rename, it test that the old filename exist and is an actual file.

  • To prevent overwriting an existing file, it uses the --no-clobber rather than the --interactive option.

Léa Gris
  • 17,497
  • 4
  • 32
  • 41