325

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).

Tim
  • 41,901
  • 18
  • 127
  • 145
Gnutt
  • 3,707
  • 4
  • 20
  • 19

28 Answers28

429

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.

Community
  • 1
  • 1
  • 1
    How do you exclude folder for being renamed ? – Merlin Feb 06 '16 at 08:48
  • 4
    legend :), I used this on git shell on windows, works great! ^^. – Mr.K Feb 24 '16 at 07:14
  • 4
    Works Great. Beauty in one line. I added ls -tr get the files by last modified time. – Ranjith Siji May 24 '16 at 07:20
  • 2
    @Lorenzo replacing `ls` with `find . -type f` will list only the files in current dir – Crawford Comeaux Aug 26 '16 at 18:26
  • 1
    It renames everything in the folder. Even ones that don't have a specific extension – DanMossa Sep 23 '16 at 07:27
  • If I understand the OP right, he want's them sorted before numbering (easy to do here with `ls -t`, hard on some other solutions) – Frank N Nov 02 '16 at 01:16
  • 63
    add printf like this: `ls | cat -n | while read n f; do mv "$f" \`printf "%04d.extension" $n\`; done` to have zero padded numbers – Seweryn Niemiec Nov 23 '16 at 19:13
  • @CrawfordComeaux as long as cwd is correct, you can do `ls | grep '.extension' | cat -n | while read n f; do mv '$f' '$n.extension'; done` and achieve the same result. I have noticed that `find` seems to order my files by another data point by default, whereas `ls` orders by filename. – Ian Dec 20 '16 at 18:19
  • Is it possible to expand this to also be able to insert the starting number for the sequence? Like if I already have `file1.txt` and `file2.txt` but want to add 4 other files I don't want the renamed sequence to start from `1` because this will override the previous 2 files. – rbaleksandar Apr 19 '17 at 18:30
  • On OSX, I thought it worked at first but ended up deleting a bunch of files, every time I run it again it adds/removes files and now I'm left with 10% the files I had, I thought it would work fine since there are no comments that mention this – Computer's Guy Aug 04 '17 at 19:49
  • 11
    Warning: You might want to add `-n` to the mv command to prevent accidentally overwriting files. Discovered this the hard way! – Ian Danforth Nov 02 '17 at 03:50
  • 12
    Putting together some great ideas from comments on this answer and others: `ls -1prt | grep -v "/$" | cat -n | while read n f; do mv -n "${f}" "$(printf "%04d" $n).${f#*.}"; done` **Results:** (1) sorted in order of modification, later files with later indexes; (2) ignores directories - and not recursive; (3) pads indexes; (4) maintains original extension. – Jorge May 22 '18 at 22:25
  • 3
    [Why you shouldn't parse the output of ls](http://mywiki.wooledge.org/ParsingLs), use `find` and filter your files properly. – rkta Jun 16 '18 at 17:26
  • You also can do this `ls | cat -n | while read n f; do EXT="${f##*.}"; mv "$f" "$n.$EXT"; done` to preserve existing extension – generall Dec 04 '18 at 08:22
  • Unfortunately this solution mess with not padded numbers `$ls: 100.flac 107.flac 113.flac 11.flac 12.flac` – Denis Trofimov Dec 27 '18 at 18:26
  • $ ls 10.png 11.png 1.png 2.png 3.png 4.png 5.png 6.png $ ls | cat -n | while read n f; do mv "$f" "$n.png"; done $ ls 7.png 8.png fantastique) – Vasilii Suricov Feb 02 '19 at 19:16
  • it is possible to add the option to make the numbers as follows: 01, 02, 03, .. ? – ambigus9 Jun 14 '19 at 20:03
  • to run in multiple folders at once: `for d in ./*/ ; do (cd "$d" && ls -v | cat -n | while read n f; do mv "$f" `printf "%03d.jpg" $n`; done); done` – hexangel616 Nov 18 '19 at 14:17
  • Just have to hop on this comment because it's really beautiful. If you don't just want to completely replace the whole filename, just increment, use this: `ls -tr | cat -n | while read n f; do mv "$f" "`printf "%02d" $n` $f"; done` This will simply increment the files, based on time modified, zero padded with two integers, with a space after the incremented prefix. e.g. "file name.mp4" -> "01 file name.mp4", incrementing using the oldest file first. – Alex Jan 20 '20 at 21:24
  • This solution does NOT work when there are specific characters in the filename, like '\'. Proof: `touch 'a\-a.pdf' && ls -v | cat -n | while read n f; do mv -n "$f" "$n.ext"; done` will fail with `mv: cannot stat 'a-a.pdf': No such file or directory` – Roel Van de Paar Nov 28 '20 at 03:36
  • Never use `ls` without `--color-never`. Hex codes will enter the data stream for color. – Roel Van de Paar Nov 28 '20 at 03:44
  • Wrote a solution which works always: https://stackoverflow.com/a/65046206/1208218 – Roel Van de Paar Dec 02 '20 at 23:28
  • An alternative to get zero padded numbers is to use `nl̦` (number lines) instead of `cat -n`. Like this: `ls | nl -n rz -w 2 | while read n f; do mv "$f" "$n.${f##*.}"` – leogama Jul 07 '21 at 19:31
  • I would recommend making the last `mv` command `mv -n -- "$f" "$n.ext"` to avoid issues with filenames that start with a `-`. – MateoConLechuga Feb 11 '23 at 03:55
  • Modified a bit based on others recommendations as well. This has zero padding and an offset in case you want the files to start at a certain number. `ls | cat -n | while read n f; do mv "$f" \`printf "%04d.extension" $(($n+offset))\`; done` – TJ Mora Apr 07 '23 at 16:37
  • ```nums=(`ls`); for i in ${!nums[@]}; do mv ${nums[$i]} $i; done``` the best with `IFS=$'\n'` – Nickotine Jun 13 '23 at 01:55
409

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.

gauteh
  • 16,435
  • 4
  • 30
  • 34
  • 8
    You can also do `printf -v new "%04d.jpg" ${a}` to put the value into the variable. And `((a++))` works to increment the variable. Also, this doesn't do it in creation date order or minimize the padding which are things the OP specified. However, it should be noted that Linux/Unix don't store a creation date. – Dennis Williamson Jul 09 '10 at 13:50
  • 3
    Could just be Cygwin (although it's terminal behaviour is largely identical to normal Unix shells) but it seems to have a problem when there are spaces in the filename. – Geesh_SO Aug 13 '13 at 09:14
  • 5
    Needed to double quote wrap the mv for this to work in my bash environment. mv "${i}" "${new}" – Gary Thomann Jul 11 '12 at 12:20
  • @Geesh_SO, that's because of the lack of quotes that Gary pointed out. – Charles Duffy Dec 03 '14 at 15:24
  • ...I've fixed that, also removing the curly braces (which served absolutely no purpose in this case). – Charles Duffy Dec 03 '14 at 15:28
  • 3
    It would probably also be desirable to use `mv -- "$i" "$new"` to correctly handle source filenames that start with dashes; as it is, `mv` will try to parse such filenames as collections of flags. – Charles Duffy Dec 03 '14 at 15:31
  • If anyone is interested in this command with the original filename preserved (and with 2 padding instead of 4): `a=1 for i in *.mp3; do new=$(printf "%02d $i" "$a"); mv -- "$i" "$new"; let a=a+1; done` – djvs Jul 03 '15 at 14:54
  • 1
    @KrIsHnA: see the note about `mv -i` in the answer. – gauteh Apr 06 '17 at 13:35
  • 3
    I have lost about 800 files at a glimpse. I think `-i`should be included in the answer and note should be rewritten accordingly. that'll be more safe. :( – Midhun KM Apr 07 '17 at 06:11
  • I like this solution because not only does it rename the files, it also pads 0's in the beginning so that the file names are all the same length. – Varun Verma Apr 16 '17 at 02:16
  • $ ls 10.png 11.png 1.png 2.png 3.png 4.png 5.png 6.png doesn't work – Vasilii Suricov Feb 02 '19 at 19:42
  • This likely will not work with files which have spaces and special chars. See https://stackoverflow.com/a/65046206/1208218 – Roel Van de Paar Dec 02 '20 at 23:36
  • Can someone please tell me what the `--` is doing here `mv -- "$i" "$new" ` ? – Eric González Aug 04 '21 at 18:35
  • @EricGonzález: see [What does -- mean?](https://unix.stackexchange.com/q/11376/201820) on Unix & Linux SE. – codeforester Mar 17 '22 at 15:36
  • I had to use declare -i a=0 in order to get bash to understand a is an integer. declare -i a=1;for i in *.jpg ; do mv -i -- "$i" "image_$a.jpg";a=a+1; done – Erwin van Dijk Oct 21 '22 at 11:04
64

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).

Pero
  • 1,371
  • 17
  • 18
  • 7
    I modified to use row number `NR` for a shorter command. `gawk '{ printf "mv %s %04d.jpg\n", $0, NR }'` – Apiwat Chantawibul Dec 21 '12 at 18:25
  • 15
    Massive security vulnerabilities here. Think about if you have a file named `$(rm -rf /).jpg`. – Charles Duffy Dec 03 '14 at 15:25
  • Thanks for pointing that out Charles. Can you suggest a safe solution? – beibei2 Dec 04 '14 at 17:59
  • 2
    breaks down in case filename has spaces. Use quotes around the source filename. printf "mv \"%s\" %04d.jpg\n", $0, a++ – baskin Feb 21 '15 at 09:04
  • 1
    The `for` loop is not taking 1 second per file, strictly speaking. It is taking a long time to fetch the 36,000 file names from the file system, then loops over them reasonably quickly. Many file systems have issues with large directories, regardless of which precise commands you run; but typically, `find` is going to be faster than a shell wildcard because it has to fetch *and sort* the list of matching files. – tripleee Jan 08 '18 at 14:21
  • @beibei2 I think this could be solved by putting each file name in single quotes so that the resulting command reads something like `mv 'original_filename' 0001.jpg`. By the way, this problem is not specific to `gawk` scripts. Even widely used patterns like `for i in *.jpg; do mv "$i" ..; done` seem to be affected by that problem. Please correct me if I am wrong ... – Binarus Jan 06 '19 at 09:04
  • 2
    @Pero Your usage of `mv` is dangerous. Besides @CharlesDuffy's objections, what happens if there (before running your script) already is a file with name `0001.jpg`, for example? It will be silently overwritten by the first file treated. Secondly, if a file happens to start with a dash, `mv` treats the rest of the file name as flags. Both problems have been mentioned in the comments to gauteh's answer, as well as their solution: Use `mv -i --` instead of `mv`. Apart from that, I agree that using `find` is better than using a shell glob, for the reason you have pointed out. – Binarus Jan 06 '19 at 09:12
  • 1
    `find` is not properly 0-terminated, so this cannot work for certain files. – Roel Van de Paar Dec 02 '20 at 23:38
48

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

Roy Shilkrot
  • 3,079
  • 29
  • 25
  • Exactly what I was looking for. I like that you can set the start index. – Jack Vial Apr 12 '18 at 23:35
  • 5
    Please note this will not keep the original *order* of the files. – Roy Shilkrot Jun 16 '18 at 01:17
  • @RoyShilkrot What do you mean by »*will not keep the original order*«? Globs in bash and other posix shells expand in sorted order according to the system's locale. Of course, this does not sort `9.ext` before `11.ext`, but other tools (like `ls`) won't do so either. – Socowi Jun 04 '20 at 05:28
  • No, this is likely a dangerous solution not to mention the fact that special chars and spaces in file names will not work correctly. – Roel Van de Paar Dec 02 '20 at 23:40
  • this is the perfect solution.. cross platform and keeps the extensions too.. well done! – supersan Jan 09 '21 at 07:52
  • this solution will result in filenames like 0001, 0002, etc. You can change `%04d` to `%01d` to have filenames like 1, 2, 3. Also be careful since this solution will rename all folders in directory as well – Dzmitry Dranitski Sep 16 '22 at 08:40
33

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.

beibei2
  • 795
  • 1
  • 7
  • 13
  • 5
    Like Pero's solution, there are security vulnerabilities here. Think about if you have a file named `$(rm -rf /).jpg`. – Charles Duffy Dec 03 '14 at 15:25
  • Thanks, this works. But you should quote the first argument to `mv`. If you have a file named i.e. `some thing.jpg` your script fails. This is what I used: `find . -name '*.jpg' | awk 'BEGIN{ a=0 }{ printf "mv \"%s"\ wallpaper-%04d.jpg\n", $0, a++ }' | bash` – klaustopher Jul 18 '15 at 13:25
  • i would probably use `-maxdepth 1` to work only on jpgs in current directory, as it's better to be safe than sorry. – Peter Perháč Sep 28 '16 at 20:24
  • If you move the pipe character to the end of the previous line, you don't need any backslashes. – tripleee Jan 08 '18 at 14:22
  • you may use `ls -1 *.jpg` instead of find, else it won't be sorted. Or add a `|sort|` before awk – JPT Dec 08 '19 at 18:49
  • This is great! if you want to keep the filenames but just prepend some numbers (say for making plex like a certain TV show that doesn't have the right file name pattern) you can use: ```find * -name '*.avi' | awk 'BEGIN{ a=0 }{ printf "ln -s \"%s\" \"%02d-%s\"\n", $0, a++, $0 }' | bash``` – deweydb Jul 03 '20 at 17:22
  • No, the `find` is not properly 0 terminated, so this cannot work. See https://stackoverflow.com/a/65046206/1208218 – Roel Van de Paar Dec 02 '20 at 23:39
32

with "rename" command

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

or

rename -N 0001 's/.*/$N.jpg/' *.jpg
Roman Rhrn Nesterov
  • 3,538
  • 1
  • 28
  • 16
  • 39
    My `rename` (Linux Mint 13) doesn't have a `-N` option. – Luke H Apr 21 '14 at 22:47
  • I can upvote just for the mention of the rename command, I have never heard of it – d.k Oct 13 '15 at 16:37
  • basically, the idea is that this command use Perl substitute regex on each file provided, so everything else is rather simple, if you have some knowledge of Perl. – d.k Oct 13 '15 at 16:40
  • 9
    I'm interested in knowing where one gets a rename command with -N option. My Ubuntu 14.04 doesn't have it. – Stephan Henningsen Dec 01 '15 at 21:19
  • 1
    I love the `rename` command, but I never knew about `-N`! Thanks! – Dan Lecocq Apr 03 '17 at 23:39
  • `rename --dry-run --lower-case --counter-format 00001 --keep-extension --expr='$_ = "$N" if @EXT' *` rename all files – OzzyCzech Apr 27 '17 at 05:21
  • The `-N` option is only available in newer versions of rename. Some distros (like raspbian) do only have an old version of it so you should update http://plasmasturm.org/code/rename – Bostrot Apr 12 '20 at 18:25
  • 3
    There are [at least three different tools known as `rename`](https://unix.stackexchange.com/q/229230/187122). The link posted by @Bostrot is yet another rename tool and it seems like @RomanRhrnNesterov used that one. ¶ To all the users of `rename` by Peder Stray and Larry Wall (package `perl-rename` on arch linux and package `rename` on debian/ubuntu): You can define `$N` yourself: `perl-rename '$N=sprintf("%04d",++$N); s/.*/$N.jpg/' *.jpg` – Socowi Jun 03 '20 at 20:51
  • How does this handle spaces and special characters and slashes in a filename? – Roel Van de Paar Dec 02 '20 at 23:40
  • What version of rename are you running that has these options (N and X)? – Raleigh L. Jul 27 '22 at 01:30
14

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
Abdala Cerqueira
  • 1,321
  • 1
  • 10
  • 12
  • 5
    Does not in fact cover all situations. A filename containing literal quotes could trivially escape -- and since you're using double quotes rather than single quotes, expansions like `$(rm -rf /)` are still honored. – Charles Duffy Dec 03 '14 at 15:26
  • This solution does cover all: https://stackoverflow.com/a/65046206/1208218 – Roel Van de Paar Dec 02 '20 at 23:29
14

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
trisweb
  • 8,814
  • 3
  • 32
  • 22
  • 6
    That's a great script, and it only depends on Perl. brew only works on macs, but you can grab it from github (https://github.com/ap/rename) and use it on Linux or Windows. – Tim Danner Feb 01 '18 at 20:47
  • 4
    this doesn't work for me. I got `Global symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at (user-supplied code).` – Anthony Chung Aug 12 '18 at 21:13
  • 1
    As a Mac user, I'm happy to report that the rename application linked to by @TimDanner is super portable, it was as easy as downloading the Zip archive, dropping the rename utility into a directory that my bash profile path is set to see, and it works right out of the box. I'm surprised this isn't available on MacPorts. I find it so weird that I have a BSD manpage for Rename (2) but when run rename it would say no command exists. Go figure. – adamlogan Oct 02 '19 at 01:57
11

NOTE The rename commands here include -n which previews the rename. To actually perform the renaming, remove the -n

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'

NOTE The rename commands here includes -n which previews the rename. To actually perform the renaming, remove the -n

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.
Luke H
  • 3,125
  • 27
  • 31
  • How can I start at a specific number using `rename`? – Jan Aug 18 '14 at 00:14
  • Does it parse spaces, double quotes, backslashes and CR's in filenames correctly? – Roel Van de Paar Dec 04 '20 at 07:18
  • When I ran the first option, it printed the new filename but never actually renamed the files to that. All I see is a bunch of lines like the following: ``` rename(20210520170654__5__88613416_141565274577465_5180391433346310275_n.mp4, 0000.mp4) rename(20210228193758__6__102160185_231347665376237_8972327157841210326_n.mp4, 0001.mp4) ``` Did you maybe forget to remove a "dry-run" option from the command? – Raleigh L. Jul 27 '22 at 01:35
  • You are correct, this argument needs to be removed, I'll update the answer – Luke H Jul 27 '22 at 23:58
6
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.

elcortegano
  • 2,444
  • 11
  • 40
  • 58
cree cree
  • 69
  • 1
  • 1
  • I used this to rename a tv show in absolute order. With printf zero padding this perfectly worked for me `find . | grep 'mkv' | nl -nrz -w3 -v1 | while read n f; do mv "$f" \`printf "Name.Year.E%03d.mkv" $n\`; done`. You can change the starting number on the `nl` part with the `-v` argument. – bachph Aug 01 '23 at 14:09
4

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

rename --counter-format 000001 --lower-case --keep-extension --expr='$_ = "$N" if @EXT' *
OzzyCzech
  • 9,713
  • 3
  • 50
  • 34
  • Does this handle spaces and special chars like slashes etc. in filenames? – Roel Van de Paar Dec 02 '20 at 23:41
  • What OS and version of rename are you running? None of those options exist on my version of rename and my OS, I get this error: ``` Unknown option: counter-format Unknown option: lower-case Unknown option: keep-extension Unknown option: expr Usage: rename [ -h|-m|-V ] [ -v ] [ -0 ] [ -n ] [ -f ] [ -d ] [ -u [enc]] [ -e|-E perlexpr]*|perlexpr [ files ] ``` I'm running Ubuntu 22 with version 1.3.0 of the rename tool – Raleigh L. Jul 27 '22 at 01:33
2

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.

Community
  • 1
  • 1
Michael Schmid
  • 4,601
  • 1
  • 22
  • 22
  • This was the most useful answer here for me, mostly because I wanted to dry-run the op before it ran, and also because I could tune the order by changing to `ls -1tU` for creation time. It also needed `rename` installed, which I didn't have. – antonyh Feb 15 '17 at 23:46
  • There are issues with this. Ref my comments on the top answer. – Roel Van de Paar Dec 02 '20 at 23:30
2

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.

Roel Van de Paar
  • 2,111
  • 1
  • 24
  • 38
2

Not related to creation date but numbered based on sorted names:

python3 -c \
'ext="jpg"
start_num=0
pad=4
import os,glob
files=glob.glob(f"*.{ext}")
files.sort()
renames=list(zip(files,range(start_num,len(files)+start_num)))
for r in renames:
  oname=r[0]
  nname=f"{r[1]:0{pad}}.{ext}"
  print(oname,"->",nname)
  os.rename(oname,nname)
'
nvd
  • 2,995
  • 28
  • 16
0

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 
Serge Stroobandt
  • 28,495
  • 9
  • 107
  • 102
Ruslan Gerasimov
  • 1,752
  • 1
  • 13
  • 20
  • 4
    Do NOT use this. Redirecting to bash like this is a massive security risk. What if one of the filename is of the form `blahblah; rm -r * blahblah.jpg`? – xhienne Jan 08 '17 at 12:29
  • No, this does not cover all special chars and spaces. See my comments on top answer. – Roel Van de Paar Dec 02 '20 at 23:32
0

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.

Paul Weibert
  • 194
  • 1
  • 4
0
a=1

for i in *.jpg; do
 mv -- "$i" "$a.jpg"
 a=`expr $a + 1`
done
beresfordt
  • 5,088
  • 10
  • 35
  • 43
Shubh
  • 25
  • 5
0

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); 
}
Andy Beverley
  • 247
  • 2
  • 5
0

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 \)

Frank N
  • 9,625
  • 4
  • 80
  • 110
  • In the grand scheme of things, many answers on this page are horrible, so maybe this doesn't particularly deserve a downvote. I hesitate to upvote anything which uses `ls` in a script, though. – tripleee Jan 08 '18 at 14:28
  • I save this answer from the negative side as while perhaps fragile, it worked for a specific use-case I had. – Ville Apr 20 '19 at 07:15
  • There are issues with this. Ref my comments on the top rated answer. – Roel Van de Paar Dec 02 '20 at 23:29
-1

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
Community
  • 1
  • 1
Adam Mendoza
  • 5,419
  • 2
  • 25
  • 31
  • 1
    Do NOT use this. Redirecting to bash like this is a massive security risk. What if one of the filename is of the form `blahblah; rm -r * blahblah.mp4`? – xhienne Jan 08 '17 at 12:38
  • And it will likely not handle certain things like spaces and special chars nor `ls` colors. – Roel Van de Paar Dec 02 '20 at 23:34
-1
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

maXp
  • 1,428
  • 1
  • 15
  • 23
  • Upvoting this answer as it only uses the native rename. My use case was to replace the first two digits of files by numbers starting at 01: `rename -v -n 's/../our $i;if(!$i){$i=1;} sprintf("%02d", $i++)/e' *` – minterior Oct 12 '18 at 06:36
  • No, special chars and spaces will not be handled correctly. Not to mention `ls` color output. – Roel Van de Paar Dec 02 '20 at 23:33
-1

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.

-1

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
-1

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

Mickael B.
  • 4,755
  • 4
  • 24
  • 48
rudr
  • 41
  • 2
-1

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

Bruno
  • 74
  • 6
-2

Here a another solution with "rename" command:

find -name 'access.log.*.gz' | sort -Vr | rename 's/(\d+)/$1+1/ge'
panticz
  • 2,135
  • 25
  • 16
-3

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
marikhu
  • 51
  • 5
  • 3
    Do NOT use this. Redirecting to bash like this is a massive security risk. What if one of the filename is of the form `blahblah; rm -r * blahblah.jpg`? Just an extreme example. – xhienne Jan 08 '17 at 13:02
-4

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.

JochenJung
  • 7,183
  • 12
  • 64
  • 113
Rick
  • 1
  • 1
    The OP asks for a set of commands in Unix Bourne Shell. You are proposing a commercial product that only runs in Windows environment. – xhienne Jan 08 '17 at 12:45