user4050567
user4050567

Reputation: 87

rename numbering within filename using shell

My files have the following pattern:

a0015_random_name.txt
a0016_some_completely_different_name.txt
a0017_and_so_on.txt
...

I would like to rename only the numbering using the shell, so that they are going two numbers down:

a0015_random_name.txt ---> a0013_random_name.txt
a0016_some_completely_different_name.txt ---> a0014_some_completely_different_name.txt
a0017_and_so_on.txt ---> a0015_and_so_on.txt

I've tried already this:

let n=15; for i in *.txt; do let n=n-2; b=`printf a00`$n'*'.txt; echo "mv $i $b"; done

(I use echo first, in order to see what would happen)

but this gave me:

mv a0015_random_name.txt a0013*.txt
mv a0016_some_completely_different_name.txt a0014*.txt
mv a0017_and_so_on.txt a0015*.txt

Also I've tried to find the command, which would set the rest of the name right, but I couldn't find it. Does someone know it, or have a better idea how to do this?

Upvotes: 1

Views: 61

Answers (2)

Your code is almost correct. Try this:

let n=15; for i in *.txt; do let n=n-2; b=`echo $i | sed "s/a[0-9]*/a$n/g`; echo "mv $i $b"; done

Better yet, to make it more robust, use the following modification:

let n=15; for i in *.txt; do let t=n-2; let n=n+1; b=`echo $i | sed "s/a00$n/a00$t/g`; echo "mv $i $b"; done

Upvotes: 4

Mark Reed
Mark Reed

Reputation: 95252

If you have the Perl rename.pl script, this is a one-liner:

rename 's/\d+/sprintf "%0${\(length $&)}d", $&-2/e' *.txt

Otherwise, it's a bit wordier. Here's one way:

for f in *.txt; do
  number=$(expr "$f" : '^[^0-9]*\([0-9]*\)') # extract the first number from the filename
  prefix=${f%%$number*}                      # remember the part before 
  suffix=${f#*$number}                       # and after the number
  let n=10#$number-2                         # subtract 2
  nf=$(printf "%s%0${#number}d%s" \
              "$prefix" "$n" "$suffix")      # build new filename
  echo "mv '$f' '$nf'"                       # echo the rename command
  # mv "$f" "$nf"                            # uncomment to actually do the rename
done

Note the 10# on the let line - that forces the number to be interpreted in base 10 even if it has leading zeroes, which would otherwise cause it to be interpreted in base 8. Also, the %0${#number}d format tells printf to format the new number with enough leading zeroes to be the same length as the original number.

On your example, the above script produces this output:

mv 'a0015_random_name.txt' 'a0013_random_name.txt' 
mv 'a0016_some_completely_different_name.txt' 'a0014_some_completely_different_name.txt' 
mv 'a0017_and_so_on.txt' 'a0015_and_so_on.txt'

Upvotes: 2

Related Questions