Help with Bash script - appending sequential numbers

Solution 1:

You can get bash to count for you just by telling it where to start, like this:

$ n=0
$ echo $((++n))
1
$ echo $((++n))
2
$ echo $((++n))
3

You can use printf %03d to format the result of $((++n)) as 001 002 003 and 010, 011 etc, for more accurate sorting. Also, there's no point setting - and _ as variables since they are not going to vary. Your function could be like this:

function rename () {
  title="photo"
  n=0
  for file in *.jpeg; do
   printf -v new "$title-$1-$2_%03d.jpeg" "$((++n))"
   mv -v -- "$file" "$new"
  done
}

Which does:

$ rename birthday 2015
'file_001.jpeg' -> 'photo-birthday-2015_001.jpeg'
'file_002.jpeg' -> 'photo-birthday-2015_002.jpeg'
'file_003.jpeg' -> 'photo-birthday-2015_003.jpeg'

But there is already a useful rename command in Ubuntu, so you may want to use a different name :)

Solution 2:

Slightly lengthy but usable python alternative. Assuming your naming is consistent with what you have in the example, you could use this function in your ~/.bashrc. ( Be mindful of the "\" characters. There must be no space after then, only newline )

rename_photos()
{
    python -c 'import os,re,sys; \
    [ os.rename(f, "photo_"+sys.argv[1]+\
      "_"+sys.argv[2]+"_"+re.split("[_.]",f)[-2]+\
      "."+re.split("[_.]",f)[-1])  \
      for f in os.listdir(".") \
    ]' "$1" "$2"
}

And call like

rename_photos arg1 arg2

Assuming your naming is consistent, what this does is splits filename into parts at "." and "_" and renames them via os.rename function

For instance:

$ ls
file_001.jpeg  file_002.jpeg  file_003.jpeg
$ rename_photos birthday 2016
$ ls
photo_birthday_2016_001.jpeg  photo_birthday_2016_002.jpeg  photo_birthday_2016_003.jpeg

Script version

Without making it overly complex, here's a small script that does the same function. There's plenty of comment to explain what each part does. The script itself has to be stored in one of the directories that belong in your $PATH variable, for instance in your ~/bin folder. Otherwise, it performs exactly the same function ( in addition to printing new filenames )

#!/usr/bin/env python
import os
import re
import sys

# The operates on all files in the current working
# directory, so you would have to cd to your folder
# and run script there. 
for item in os.listdir("."):

    # We don't wanna rename the script itself ( just in case ) and
    # we don't
    if os.path.join("./" + item) != __file__ and \
       os.path.isfile("./" + item):
           title="photo_"

           # Old name can be split into parts using _ and . as 
           # separators, so we only take items between those as one.
           # The last item (-1) is extension, and the one
           # before extension is number
           old_name = re.split("[_.]",item)
           new_name = sys.argv[1] + sys.argv[2] + "_" \
                      + old_name[-2] + "." + old_name[-1]

           print(new_name)
           os.rename(item,new_name)

Solution 3:

What I understood, you just want to add sequential numbers to the end. I would personally do this

 function rename () {
  count=1           #The first photo will get number 1 to the end
  title="photo"
  h="-"
  u="_"
  new=$title$h$1$h$2$u
  for file in *.jpeg; do
    if [ $count -lt 10 ]; then
        mv -v "$file" "${new}00$count" #numbers 1-9 will be like 001 002..
    elif [ $count -lt 100 ]; then
        mv -v "$file" "${new}0$count" #numbers 10-99 like 022 056 etc..
    else
        mv -v "$file" "$new$count"
    fi
    count=$[ $count + 1 ]      #count variable gets bigger by one 
  done
}

When the files are renamed, they will get sequential numbers with padding to the end. This could be done differently like indicated in other answers, but I find this pretty easy to understand in case a person doesn't have very good knowledge of bash scripting

Hope this helps!

Solution 4:

You can decide for yourself which is the easier way.

Extracting old numbers

You can get the numbers in your filename with a command like grep:

number=$(egrep -o '[0-9]+' <<< "$file")

The command above saves any sequence of digits (matched by the pattern '[0-9]+') in the variable file (passed in to grep through <<<) to the variable number.

Generating new numbers

You can try something like the below:

number=0 # initialize number to 0
for file in *.jpeg; do
    ... # do some stuff here
    ((number+=1)) # adds 1 to the variable number
done

This generates a number starting from 0 for each of your files.

It may be useful to have numbers formated with a fixed width (i.e. 001 instead of 1) for sorting purposes. In which case you can use printf to get a desired output:

number_formatted="$(printf "%03d" "$number")"

The code above formats "12" as "012" and "321" as "321". The "%03d" specifies the format (0 means prepend 0 to the number, 3 specifies 3 total digits printed, including any 0s).