Renaming files in a folder to sequential numbers

BashRenameBatch Rename

Bash Problem Overview


I want to rename the files in a directory to sequential numbers. Based on creation date of the files.

For Example sadf.jpg to 0001.jpg, wrjr3.jpg to 0002.jpg and so on, the number of leading zeroes depending on the total amount of files (no need for extra zeroes if not needed).

Bash Solutions


Solution 1 - Bash

Try to use a loop, let, and printf for the padding:

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

using the -i flag prevents automatically overwriting existing files, and using -- prevents mv from interpreting filenames with dashes as options.

Solution 2 - Bash

Beauty in one line:

ls -v | cat -n | while read n f; do mv -n "$f" "$n.ext"; done 

You can change .ext with .png, .jpg, etc.

Solution 3 - Bash

I like gauteh's solution for its simplicity, but it has an important drawback. When running on thousands of files, you can get "argument list too long" message (more on this), and second, the script can get really slow. In my case, running it on roughly 36.000 files, script moved approx. one item per second! I'm not really sure why this happens, but the rule I got from colleagues was "find is your friend".

find -name '*.jpg' | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

To count items and build command, gawk was used. Note the main difference, though. By default find searches for files in current directory and its subdirectories, so be sure to limit the search on current directory only, if necessary (use man find to see how).

Solution 4 - Bash

A very simple bash one liner that keeps the original extensions, adds leading zeros, and also works in OSX:

num=0; for i in *; do mv "$i" "$(printf '%04d' $num).${i#*.}"; ((num++)); done

Simplified version of http://ubuntuforums.org/showthread.php?t=1355021

Solution 5 - Bash

using Pero's solution on OSX required some modification. I used:

find . -name '*.jpg' \
| awk 'BEGIN{ a=0 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' \
| bash

note: the backslashes are there for line continuation

edit July 20, 2015: incorporated @klaustopher's feedback to quote the \"%s\" argument of the mv command in order to support filenames with spaces.

Solution 6 - Bash

with "rename" command

rename -N 0001 -X 's/.*/$N/' *.jpg

or

rename -N 0001 's/.*/$N.jpg/' *.jpg

Solution 7 - Bash

To work in all situations, put a " for files that have space in the name

find . -name '*.jpg' | gawk 'BEGIN{ a=1 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' | bash

Solution 8 - Bash

If your rename doesn't support -N, you can do something like this:

ls -1 --color=never -c | xargs rename -n 's/.*/our $i; sprintf("%04d.jpg", $i++)/e'

Edit To start with a given number, you can use the (somewhat ugly-looking) code below, just replace 123 with the number you want:

ls -1 --color=never  -c | xargs rename -n 's/.*/our $i; if(!$i) { $i=123; } sprintf("%04d.jpg", $i++)/e'

This lists files in order by creation time (newest first, add -r to ls to reverse sort), then sends this list of files to rename. Rename uses perl code in the regex to format and increment counter.

However, if you're dealing with JPEG images with EXIF information, I'd recommend exiftool

This is from the exiftool documentation, under "Renaming Examples"

   exiftool '-FileName<CreateDate' -d %Y%m%d_%H%M%S%%-c.%%e dir

   Rename all images in "dir" according to the "CreateDate" date and time, adding a copy number with leading '-' if the file already exists ("%-c"), and
   preserving the original file extension (%e).  Note the extra '%' necessary to escape the filename codes (%c and %e) in the date format string.

Solution 9 - Bash

On OSX, install the rename script from Homebrew:

brew install rename

Then you can do it really ridiculously easily:

rename -e 's/.*/$N.jpg/' *.jpg

Or to add a nice prefix:

rename -e 's/.*/photo-$N.jpg/' *.jpg

Solution 10 - Bash

Follow command rename all files to sequence and also lowercase extension:

rename --counter-format 000001 --lower-case --keep-extension --expr='$_ = "$N" if @EXT' *

Solution 11 - Bash

find .  | grep 'avi' | nl -nrz -w3 -v1 | while read n f; do mv "$f" "$n.avi"; done

find . will display all file in folder and subfolders.

grep 'avi' will filter all files with avi extension.

nl -nrz -w3 -v1 will display sequence number starting 001 002 etc following by file name.

while read n f; do mv "$f" "$n.avi"; done will change file name to sequence numbers.

Solution 12 - Bash

Again using Pero's solution with little modifying, because find will be traversing the directory tree in the order items are stored within the directory entries. This will (mostly) be consistent from run to run, on the same machine and will essentially be "file/directory creation order" if there have been no deletes.

However, in some case you need to get some logical order, say, by name, which is used in this example.

find -name '*.jpg' | sort -n | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command 

Solution 13 - Bash

I had a similar issue and wrote a shell script for that reason. I've decided to post it regardless that many good answers were already posted because I think it can be helpful for someone. Feel free to improve it!

numerate

@Gnutt The behavior you want can be achieved by typing the following:

./numerate.sh -d <path to directory> -o modtime -L 4 -b <startnumber> -r

If the option -r is left out the reaming will be only simulated (Should be helpful for testing).

The otion L describes the length of the target number (which will be filled with leading zeros) it is also possible to add a prefix/suffix with the options -p <prefix> -s <suffix>.

In case somebody wants the files to be sorted numerically before they get numbered, just remove the -o modtime option.

Solution 14 - Bash

a=1

for i in *.jpg; do
 mv -- "$i" "$a.jpg"
 a=`expr $a + 1`
done

Solution 15 - Bash

Let us assume we have these files in a directory, listed in order of creation, the first being the oldest:

a.jpg
b.JPG
c.jpeg
d.tar.gz
e

then ls -1cr outputs exactly the list above. You can then use rename:

ls -1cr | xargs rename -n 's/^[^\.]*(\..*)?$/our $i; sprintf("%03d$1", $i++)/e'

which outputs

rename(a.jpg, 000.jpg)
rename(b.JPG, 001.JPG)
rename(c.jpeg, 002.jpeg)
rename(d.tar.gz, 003.tar.gz)
Use of uninitialized value $1 in concatenation (.) or string at (eval 4) line 1.
rename(e, 004)

The warning ”use of uninitialized value […]” is displayed for files without an extension; you can ignore it.

Remove -n from the rename command to actually apply the renaming.

This answer is inspired by Luke’s answer of April 2014. It ignores Gnutt’s requirement of setting the number of leading zeroes depending on the total amount of files.

Solution 16 - Bash

The majority of the other solutions will overwrite existing files already named as a number. This is particularly a problem if running the script, adding more files, and then running the script again.

This script renames existing numerical files first:

#!/usr/bin/perl

use strict;
use warnings;

use File::Temp qw/tempfile/;

my $dir = $ARGV[0]
    or die "Please specify directory as first argument";

opendir(my $dh, $dir) or die "can't opendir $dir: $!";

# First rename any files that are already numeric
while (my @files = grep { /^[0-9]+(\..*)?$/ } readdir($dh))
{
    for my $old (@files) {
        my $ext = $old =~ /(\.[^.]+)$/ ? $1 : '';
        my ($fh, $new) = tempfile(DIR => $dir, SUFFIX => $ext);
        close $fh;
        rename "$dir/$old", $new;
    }
}

rewinddir $dh;
my $i;
while (my $file = readdir($dh))
{
    next if $file =~ /\A\.\.?\z/;
    my $ext = $file =~ /(\.[^.]+)$/ ? $1 : '';
    rename "$dir/$file", sprintf("%s/%04d%s", $dir, ++$i, $ext); 
}

Solution 17 - Bash

Sorted by time, limited to jpg, leading zeroes and a basename (in case you likely want one):

ls -t *.jpg | cat -n |                                           \
while read n f; do mv "$f" "$(printf thumb_%04d.jpg $n)"; done

(all on one line, without the \)

Solution 18 - Bash

I spent 3-4 hours developing this solution for an article on this: https://www.cloudsavvyit.com/8254/how-to-bulk-rename-files-to-numeric-file-names-in-linux/

if [ ! -r _e -a ! -r _c ]; then echo 'pdf' > _e; echo 1 > _c ;find . -name "*.$(cat _e)" -print0 | xargs -0 -t -I{} bash -c 'mv -n "{}" $(cat _c).$(cat _e);echo $[ $(cat _c) + 1 ] > _c'; rm -f _e _c; fi

This works for any type of filename (spaces, special chars) by using correct \0 escaping by both find and xargs, and you can set a start file naming offset by increasing echo 1 to any other number if you like.

Set extension at start (pdf in example here). It will also not overwrite any existing files.

Solution 19 - Bash

Using sed :

ls -tr | sed "s/(.*)/mv '\1' \=printf('%04s',line('.').jpg)/" > rename.sh
bash rename.sh

This way you can check the script before executing it to avoid big mistakes

Solution 20 - Bash

ls -1tr | rename -vn 's/.*/our $i;if(!$i){$i=1;} sprintf("%04d.jpg", $i++)/e'

rename -vn - remove n for off test mode

{$i=1;} - control start number

"%04d.jpg" - control count zero 04 and set output extension .jpg

Solution 21 - Bash

To me this combination of answers worked perfectly:

ls -v | gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | bash
  • ls -v helps with ordering 1 10 9 in correct: 1 9 10 order, avoiding filename extension problems with jpg JPG jpeg
  • gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' renumbers with 4 characters and leading zeros. By avoiding mv I do not accidentally try to overwrite anything that is there already by accidentally having the same number.
  • bash executes

Be aware of what @xhienne said, piping unknown content to bash is a security risk. But this was not the case for me as I was using my scanned photos.

Solution 22 - Bash

Here is what worked for me.
I Have used rename command so that if any file contains spaces in name of it then , mv command dont get confused between spaces and actual file.

Here i replaced spaces , ' ' in a file name with '_' for all jpg files

#! /bin/bash
rename 'y/ /_/' *jpg         #replacing spaces with _
let x=0;
for i in *.jpg;do
let x=(x+1)
mv $i $x.jpg
done

Solution 23 - Bash

Nowadays there is an option after you select multiple files for renaming (I have seen in thunar file manager).

  1. select multiple files
  2. check options
  3. select rename

A prompt comes with all files in that particular dir just check with the category section

Solution 24 - Bash

This script will sort the files by creation date on Mac OS bash. I use it to mass rename videos. Just change the extension and the first part of the name.

ls -trU *.mp4| awk 'BEGIN{ a=0 }{ printf "mv %s lecture_%03d.mp4\n", $0, a++ }' | bash

Solution 25 - Bash

Here a another solution with "rename" command:

find -name 'access.log.*.gz' | sort -Vr | rename 's/(\d+)/$1+1/ge'

Solution 26 - Bash

Pero's answer got me here :)

I wanted to rename files relative to time as the image viewers did not display images in time order.

ls -tr *.jpg | # list jpegs relative to time
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

Solution 27 - Bash

To renumber 6000, files in one folder you could use the 'Rename' option of the ACDsee program.

For defining a prefix use this format: ####"*"

Then set the start number and press Rename and the program will rename all 6000 files with sequential numbers.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGnuttView Question on Stackoverflow
Solution 1 - BashgautehView Answer on Stackoverflow
Solution 2 - Bashuser4434168View Answer on Stackoverflow
Solution 3 - BashPeroView Answer on Stackoverflow
Solution 4 - BashRoy ShilkrotView Answer on Stackoverflow
Solution 5 - Bashbeibei2View Answer on Stackoverflow
Solution 6 - BashRoman Rhrn NesterovView Answer on Stackoverflow
Solution 7 - BashAbdala CerqueiraView Answer on Stackoverflow
Solution 8 - BashLuke HView Answer on Stackoverflow
Solution 9 - BashtriswebView Answer on Stackoverflow
Solution 10 - BashOzzyCzechView Answer on Stackoverflow
Solution 11 - Bashcree creeView Answer on Stackoverflow
Solution 12 - BashRuslan GerasimovView Answer on Stackoverflow
Solution 13 - BashPaul WeibertView Answer on Stackoverflow
Solution 14 - BashShubhView Answer on Stackoverflow
Solution 15 - BashMichael SchmidView Answer on Stackoverflow
Solution 16 - BashAndy BeverleyView Answer on Stackoverflow
Solution 17 - BashFrank NockeView Answer on Stackoverflow
Solution 18 - BashRoel Van de PaarView Answer on Stackoverflow
Solution 19 - BashBrunoView Answer on Stackoverflow
Solution 20 - BashmaXpView Answer on Stackoverflow
Solution 21 - BashnintendojetView Answer on Stackoverflow
Solution 22 - Bashrishang bhavsarView Answer on Stackoverflow
Solution 23 - BashrudrView Answer on Stackoverflow
Solution 24 - BashAdam MendozaView Answer on Stackoverflow
Solution 25 - BashpanticzView Answer on Stackoverflow
Solution 26 - BashmarikhuView Answer on Stackoverflow
Solution 27 - BashRickView Answer on Stackoverflow