4

I am using the following code to rename all the images in the current folder:

a=1
for i in *.jpg; do
  new=$(printf "%04d.jpg" ${a}); #04 pad to length of 4
  mv ${i} ${new};
  a=$((a+1));
done

But I have met a problem: some of the images were overwritten, because I use it after I have added more images in the folder. Is there a way to fix this? I thought to add an if (name_exists) then next_name, but I am new to scripts. Any help, please?

clt60
  • 62,119
  • 17
  • 107
  • 194
sop
  • 3,445
  • 8
  • 41
  • 84
  • 1
    `-n` option for no-clobber? – Marc B Oct 13 '14 at 11:52
  • If you just want to get the job done, create a sub-directory in current directory, `mv ${i} tmpdir/${new}` & then move all the .jpg files from tmpdir to current directory. (Assuming that there will not be new files getting added in current directiory, while operation is going on. – anishsane Oct 13 '14 at 11:55
  • What does it happen if I use the -n flag? Does it nor rename the current file or it does increment a until it finds a possible name? – sop Oct 13 '14 at 12:05
  • With the `-n` option, the renaming will just fail, and the file is skipped. – gniourf_gniourf Oct 13 '14 at 12:58

2 Answers2

2

You can use:

#!/bin/bash
glob="[0-9][0-9][0-9][0-9].jpg"
last=$(find . -maxdepth 1 -name "$glob" -print |sort -gr |grep -Pom1 '\d{4}') # or  |grep -om1 '[0-9][0-9]*')
last=${last:-0}
while IFS= read -d $'\0' -r image
do
    let last++
    echo mv "$image" "$(printf "%04s" $last ).jpg"
done < <(find . -maxdepth 1 -name \*.jpg -a -not -name "$glob" -print0)

where:

  • 1st find finds the last used number
  • the while read reads the output from the
  • 2nd find what finds all .jpg what have different name as NNNN.jpg
  • increment and rename

You can imprpve this

  • search other types of images (not only jpg)
  • change the script to case insensitive
  • the above will fail if the image count raises above 9999... so...

The script is in dry mode, remove the echo when satisfied

EDIT

dash version:

glob="[0-9][0-9][0-9][0-9].jpg"
last=$(find . -maxdepth 1 -name "$glob" -print |sort -gr |grep -Pom1 '\d{4}') # or  |grep -om1 '[0-9][0-9]*')
last=${last:-0}
for image in *.jpg
do
    echo "$image" | grep -q "^$glob$" && continue
    #last=$((last+1))  #with leading zeroes, the numbers treated as octal... fails for 08 and such
    last=$(expr $last + 1)
    echo mv "$image" "$(printf "%04d" $last ).jpg"
done
clt60
  • 62,119
  • 17
  • 107
  • 194
  • Why do I get `Syntax error: redirection unexpected`? – sop Oct 13 '14 at 12:48
  • Still the same error, I think that it is something about my bash, because I had strange error when trying something else (see [these comments](http://stackoverflow.com/a/26213144/3062311)) – sop Oct 13 '14 at 13:02
  • 2
    @sop you don't using `bash` but `dash`. If you want `dash` script, don't tag your question as `bash`... The default shell in ubuntu is `dash` not `bash`... omg.. ;( The `Syntax error: redirection unexpected` is an `dash's` error message. – clt60 Oct 13 '14 at 13:03
  • Thanks for idea. How to do it in dash? :) – sop Oct 13 '14 at 13:14
  • How to fix this: `7: Illegal number: 0018`? Is it possible to keep the 0s in front? – sop Oct 13 '14 at 14:46
  • @sop - if you not edited the script - e.g. copy it EXACTLY, you can't have spaces in the destination filename, the `"$(printf "%04d" $last ).jpg"` create a filename **without** any space. – clt60 Oct 13 '14 at 16:06
  • And it renames only the files that have not the wanted format? – sop Oct 13 '14 at 16:12
  • @sop - yes. but, please test it yourself. If not doing what you want, leave it - if doing what you want accept it.. ;) The minimal understanding what the script does is needed... – clt60 Oct 13 '14 at 16:15
0

add the following to your script

a=1
for i in *.jpg; do
    new=$(printf "%04d.jpg" ${a});
    while [ -f ${new} ]
    do
       a=$((a+1));
       new=$(printf "%04d.jpg" ${a});
    done
    mv ${i} ${new};
    a=$((a+1));
done

if you are not too particular about the numbered names. You could use this:

if [ -f ${new} ]
then
    new=$(printf "%04d_%s.jpg" ${a} $(date +'%H_%M_%S'))
fi

instead of while.

Satyajit R
  • 72
  • 4
  • I really like the idea of the date, like this I'll always have a `0001` image. – sop Oct 13 '14 at 12:46
  • 4
    This will rename the existing `0001.jpg` to the next avaliable number such `0111.jpg`. The `for` get `0001.jpg` the `while` will search for the next available number and rename it... – novacik Oct 13 '14 at 13:17