Rename all files in a folder to consecutive numbers

10,466

Solution 1

Assuming you want to follow the shell globbing order while sorting files, you can do:

#!/bin/bash
counter=0
for file in *; do 
    [[ -f $file ]] && echo mv -i "$file" $((counter+1)).png && ((counter++))
done

Here looping over all the files in the current directory and renaming sequentially based on order, if you want to deal with only the .png files, use for file in *.png instead. counter variable will keep track of the increments.

This is a dry-run, remove echo to let the actual renaming action take place.

Example:

$ counter=0; for file in *; do [[ -f $file ]] && echo mv -i "$file" $((counter+1)).png && ((counter++)); done
mv -i file.txt 1.png
mv -i foo.sh 2.png
mv -i bar.txt 3.png

Solution 2

Here's a small python script that can do what you ask

Basic usage:

python rename_files.py Pictures/

It will print output to stdout before renaming each file

This version pushes index until it is found that filename with such index is not taken. Although filenames may start at different index upon successive iterations of the script, the files themselves remain unchanged.

import os
import sys

top_dir = os.path.abspath(sys.argv[1])
files = os.listdir( top_dir )

for index,item in enumerate(files):
    if os.path.isdir( os.path.join(top_dir,item) ):
       files.pop(index)

files.sort()

duplicates = []
last_index = None
for index,item in enumerate(files):

    last_index = index
    extension = ""
    if '.' in item:
        extension = '.' + item.split('.')[-1]
    old_file = os.path.join(top_dir,item)
    new_file = os.path.join(top_dir,str(index) + extension  )
    while os.path.isfile(new_file):
          last_index += 1
          new_file = os.path.join(top_dir,str(last_index) + extension  )
    print( old_file + ' renamed to ' + new_file ) 
    os.rename(old_file,new_file)

Alternative version, solves issue with duplicate filenames by appending timestamp to each filename, and then enumerating them. This solution may take longer time, as number of files increases, but for directories that range in hundreds , this won't take long time

import os
import sys
import time

top_dir = os.path.abspath(sys.argv[1])
files = os.listdir( top_dir )

for index,item in enumerate(files):
    if os.path.isdir( os.path.join(top_dir,item) ):
       files.pop(index)

files.sort()
timestamp = str(int(time.time()))
for item in files:
    os.rename( os.path.join(top_dir,item) ,
               os.path.join(top_dir, timestamp + item) )

files2 = os.listdir( top_dir )

for index,item in enumerate(files2):
    if os.path.isdir( os.path.join(top_dir,item) ):
       files2.pop(index)

for index,item in enumerate( files2  ):

    last_index = index
    extension = ""
    if '.' in item:
        extension = '.' + item.split('.')[-1]
    old_file = os.path.join(top_dir,item)
    new_file = os.path.join(top_dir,str(index) + extension  )

    while os.path.isfile(new_file):
          last_index += 1
          new_file = os.path.join(top_dir,str(last_index) + extension  )
    print( old_file + ' renamed to ' + new_file ) 
    os.rename(old_file,new_file)
Share:
10,466

Related videos on Youtube

Adam
Author by

Adam

Updated on September 18, 2022

Comments

  • Adam
    Adam over 1 year

    I would like to rename all files in a folder so to have consecutive numbers. For instance:

    1.png
    2.png
    3.png
    etc
    

    I know there is the rename command and I know there are DOZENS of similar questions in here but I can't find the way.

    NOTE: Suggested duplicate doesn't contain a solution specific for my case. Please stop flagging this as duplicate, because suggested duplicate does not answer my question

    • heemayl
      heemayl almost 8 years
      Which file will be 1.png? Shell globbing order?
    • Adam
      Adam almost 8 years
      @heemayl I don't really understand what you mean but the 1.png I want to be the first file in the folder.
    • wjandrea
      wjandrea almost 8 years
      @Adam He's asking how you have the files sorted. The shell sorts them one way according to name, but you might want them sorted by last modified date, a different way by name, etc.
    • Sergiy Kolodyazhnyy
      Sergiy Kolodyazhnyy almost 8 years
      You might want to provide example of how files are named in the folder. This can be easily done, but we need to know what the original filenams will be.
    • Adam
      Adam almost 8 years
      @wjandrea Oh I want them sorted based on their name i.e. 1 first 2 second etc...
    • Adam
      Adam almost 8 years
      @Serg The files are named with the default name of the Screenshot software of Ubuntu.
    • Sergiy Kolodyazhnyy
      Sergiy Kolodyazhnyy almost 8 years
      Ok , let me sketch up a small script, i'll post it in about 20 mins or so
    • Sergiy Kolodyazhnyy
      Sergiy Kolodyazhnyy almost 8 years
      By the way , what if the folder contains subfolders ? Leave those alone or give it a number as well ?
    • Sergiy Kolodyazhnyy
      Sergiy Kolodyazhnyy almost 8 years
      Posted answer, please review
    • Sergiy Kolodyazhnyy
      Sergiy Kolodyazhnyy almost 8 years
      CLOSE-VOTERS: as shown in the comments, OP specifically stated that he tried the suggested duplicate and it did not work. Please retract your votes. See meta.stackexchange.com/a/194479/295160
  • wjandrea
    wjandrea almost 8 years
    You should put quotes around $file to avoid breaking on spaces, and put ((counter++)) inside an if statement to avoid incrementing on directories.
  • heemayl
    heemayl almost 8 years
    @wjandrea You don't need to quote when using bash keyword [[ (unlike [), [[ is a keyword, bash handles it internally as well as the word splitting and filename expansion too, hence no quoting needed. You're right about the second one, forgot that. Edited..thanks..
  • Dave Tweed
    Dave Tweed almost 8 years
    Don't forget to check whether any of your destination filenames already exists in the directory. Suppose you run the script once, add a few files, and then try to run it again. What happens?
  • Dave Tweed
    Dave Tweed almost 8 years
    Don't forget to check whether any of your destination filenames already exists in the directory. Suppose you run the script once, add a few files, and then try to run it again. What happens?
  • heemayl
    heemayl almost 8 years
    @DaveTweed that's what the -i option of mv will do..
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy almost 8 years
    @DaveTweed can you provide an example ? running script twice wouldn't have issue with duplicates, because entries are sorted and enumerated each time. So if 1.png already exists, it would get sorted and renamed to 1.png again
  • Dave Tweed
    Dave Tweed almost 8 years
    What is what the -i option does? Even if you skip overwriting a file, you still won't end up with the correct result.
  • Dave Tweed
    Dave Tweed almost 8 years
    Suppose I run the script to produce 1.png through 10.png. Then I add the file 3a.png, which should be renamed to 4.png, which already exists -- not to mention the renaming all of the files after that.
  • Dave Tweed
    Dave Tweed almost 8 years
    Note that just having 1.png through 10.png by itself is a problem -- on the second run, you'll want to rename 10.png to 2.png, creating the same problem.
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy almost 8 years
    @DaveTweed is this the case you mean ? paste.ubuntu.com/22518702
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy almost 8 years
    Also, how's this ? paste.ubuntu.com/22518907
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy almost 8 years
    I get what you're saying, but do you have any suggestion on how to avoid overwriting duplicates ?
  • Dave Tweed
    Dave Tweed almost 8 years
    There are two issues here. The first is producing a sequence of output filenames that sorts to the same sequence when read as input. The second issue is the problem of overwriting an existing file.The latter must be addressed by forming a complete mapping from input names to output names, and then before you rename any files, you check for any collisions between the two lists. If any are found, they form "chains" of two or more names that must be handled last-first. I.e., you must rename 4.png to 5.png before you try to rename 3a.png to 4.png, and so forth.
  • Dave Tweed
    Dave Tweed almost 8 years
    ... This is the difference between "software engineering" and simple hacking.
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy almost 8 years
    @DaveTweed OK , I've edited my script somewhat to push index until there's no index that exists. Please check this: paste.ubuntu.com/22526386 Updated script is here: paste.ubuntu.com/22526509
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy almost 8 years
    Here's one more with extensions paste.ubuntu.com/22526962
  • Sergiy Kolodyazhnyy
    Sergiy Kolodyazhnyy almost 8 years
  • heemayl
    heemayl almost 8 years
    @DaveTweed Ahhh..i see what you meant. That would need a hash and some preprocessing..this answer is necessarily an one go..
  • Jsevillamol
    Jsevillamol about 5 years
    In case somebody wants the result to be zero-padded, you can use counter=0; for file in *; do [[ -f $file ]] && echo mv -i "$file" $(printf %03d $((counter+1))).png && ((counter++)); done