203

I have a directory full of images:

image0001.png
image0002.png
image0003.png
...

And I would like a one-liner to rename them to (say).

0001.png
0002.png
0003.png
...

How do I do this?

Internet man
  • 3,641
  • 8
    This is one of the top Unix command line FAQs, and I can't find it on this site already, so should we make this Community Wiki? – Gilles 'SO- stop being evil' Aug 24 '10 at 00:08
  • 6
    I don't see why. It's a specific question with a verifiable answer. – Internet man Aug 24 '10 at 00:45
  • 3
    If you're running X it doesn't get much easier than thunar -B *.png for thunar's bulk-rename gui tool. – dotjoe Aug 25 '10 at 21:26
  • @dotjoe Thunar is not common to all X-based desktop environments. It would be better to say, "If you're running Xfce, it doesn't..." or "If you've installed Thunar, it doesn't..." – chb Feb 19 '24 at 04:53

14 Answers14

147

On Debian and derivatives, Perl's rename commandline works similarly to sed like this:

  rename -v 's/image//' ./*.png

There's also the rename from util-linux that works like this, instead:

  rename -- image '' *.png
Internet man
  • 3,641
  • 13
    you really should explain that this is a perl programm that might have to be installed and that it takes regular expressions as the argument. –  Aug 24 '10 at 00:30
  • Ah, I was not aware of that. I'll give credit to the canonical answer, when I identify it :) – Internet man Aug 24 '10 at 00:33
  • 6
    This rename program came from a Perl examples distribution. Debian and Ubuntu ship it as /usr/bin/rename. Other Unix variants may not provide it, or may provide a completely different /usr/bin/rename. – Gilles 'SO- stop being evil' Aug 24 '10 at 07:17
  • On some systems it may be called prename. There is also more than one version of it, regardless of how it's named. – Dennis Williamson Aug 26 '10 at 00:13
  • 2
    Some versions of rename take a from to replacement pattern: rename [options] <expression> <replacement> <file>... – melds Dec 29 '15 at 18:42
  • 1
    If you are using a Debian based system then sudo apt-get install rename, then you can use the rename command. It is sed for filenames. – ctrl-alt-delor Dec 31 '16 at 17:20
  • I wrote a script using perls rename and only now realised that it is SUPER SLOW. It can't even process 10 files in a second, which is really annoying if you work with thousands of files... – xeruf Sep 09 '18 at 12:08
  • Thank you! I was thinking I was using Perl's rename, and it wasn't working! I guess I was using util-linux. 3 hours I tried to debug this! – hunkah May 17 '21 at 05:12
  • I use lubuntu and have rename.ul pre-installed. – Timo Jun 05 '21 at 19:53
  • FYI for the version of rename that installs with apt install rename in ubuntu, the -e flag must be used in place of -v: rename -e 's/image//' ./*.png – twhitney Feb 02 '24 at 22:02
132

If you are using Bash or other POSIX-compatible shell:

for f in *.png; do
    mv -- "$f" "${f#image}"
done
ilkkachu
  • 138,973
W_Whalley
  • 1,827
68

The zsh shell has a powerful batch rename command called zmv.

First you need to enable the zmv command as follows (this can go into your ~/.zshrc).

autoload zmv

The basic syntax is zmv PATTERN REPLACEMENT. The pattern is a shell glob expression. Parts of the pattern can be surrounded by parentheses. The replacement text can contain $1, $2, etc. to refer to the Nth parenthesised group in the pattern. For example:

zmv 'image(*.png)' '$1'

You can also ask zsh to automatically define $1, $2, etc. to match the wildcard characters in the pattern:

zmv -w 'image*.png' '$1.png'
bfontaine
  • 163
  • Really cool, as pointed in zmv's man this can be further simplified by adding alias mmv='noglob zmv -W' to: mmv *.c.orig orig/*.c – Bretsko Aug 29 '17 at 16:10
  • Enabling zmv prezto requires uncommenting the line in your ~/.zpreztorc following # Set the Zsh functions to load (man zshcontrib). giving zstyle ':prezto:load' zfunction 'zargs' 'zmv' –  Apr 01 '19 at 21:51
  • For those who, (like me) rarely need to rename files, you don't need to put autoload zmv in your ~/.zshrc: you can also just run it whenever you need zmv. – Niek Sep 18 '20 at 08:08
52

I normally use the nice and simple mmv (man page) utility for this usecase:

$ mmv "image*.png" "#1.png"

will perform your task.

The #1 in the target pattern will be substituted with whatever matches the wildcard in the source pattern. This also works for several wildcards and can be used for example to change the order of parts of filenames. You can also easily do more complicated things like converting lower case to upper case letters.

Make sure to protect the patterns from the shell by quoting.

13

POSIX sh for loop

Uses sed to rename

for i in image*.png
do 
  mv -i -- "$i" "$(printf '%s\n' "$i" | sed '1s/^image//')"
done
X Tian
  • 10,463
13

qmv

The command qmv from renameutils opens an editor showing a list of filenames with two colums, separated by a tab. Each row shows one of the filenames, the same in both columns. The right column is representing the new names of the files.
To make changes, edit the names on the right side. In this example, :%s/... or visual block mode are helpful.

Filenames in your editor

$ qmv *.png

In editor:

image0001.png           image0001.png
image0002.png           image0002.png
image0003.png           image0003.png         
~                                             
~                                             
~                                             
~                                             
"/tmp/user/1000/qmvxWyVMs" 3L, 93C

Edit names in right column:
(Removing the image prefix from all lines using visual block mode)

image0001.png           0001.png
image0002.png           0002.png
image0003.png           0003.png         
~                                             
~                                             
~                                             
~                                             
:wq

Log of renaming:

image0001.png -> 0001.png
image0002.png -> 0002.png
image0003.png -> 0003.png

(e.g. Ubuntu: apt-get install renameutils)

Volker Siegel
  • 17,283
5

I like Perl so:

perl -nlE '$old=$_; s/image//; qx(mv $old $_)'

You can also use the same pattern for other tasks like copying the files to another directory:

perl -nlE '$old=$_; s(image)(/path/to/new/dir/); qx(mv $old $_)'
gvkv
  • 2,738
  • 4
    Or (safer!): rename($old,$_) – reinierpost Aug 07 '14 at 11:57
  • 1
    Yes, calling sh and mv for every file is both inefficient and very dangerous. That code is basically a command injection vulnerability. The list of files would also need to be supplied somehow on perl's stdin, but as it's expected newline-delimited it can't take arbitrary file names. – Stéphane Chazelas Dec 02 '22 at 14:56
3

recursive

easy recurse selecting image*png files, and assumes no need to deal with newline, backslash in file names

find . -name "image*.png" | while read f; do mv -v "$f" "$(echo "$f" | sed -e 's/image//' - )"; done
X Tian
  • 10,463
  • Your solution here can't deal with newlines. It also depends on echo not modifying data, which it could do if it contains backslashes under some circumstances. – Kusalananda Mar 19 '21 at 10:16
  • @Kusalananda - Thank you, I have removed incorrect 2nd answer. – X Tian Mar 19 '21 at 17:22
3

Using a shells that supports brace expansion (Bash, Zsh, Ksh93, Fish, Csh, Tcsh):

for N in {0001..1000}; do mv "{image,}$N.png"; done
αғsнιη
  • 41,407
1

POSIX sh using a while loop

Reading names from find command.

find . ! -path . -prune -type f -name 'image*png' |
while IFS= read -r f; do
  mv "$f" "$(printf '%s\n' "$f" | sed -e 's/^\.\/image//' - )"
done

Reading names from a file

while IFS= read -r f; do
  mv "$f" "$(printf '%s\n' "$f" | sed -e 's/^\.\/image//' - )"
done < flist

Both of these approaches assume pathnames have no embedded newlines.

Kusalananda
  • 333,661
X Tian
  • 10,463
1

Try brename (https://github.com/shenwei356/brename), a practical cross-platform command-line tool for safely batch renaming files/directories via regular expression (supporting Windows, Linux and OS X) .

@patrickDurusau said:

Linux has a variety of batch file renaming options but I didn’t see any short-comings in brename that jumped out at me.

Features:

  • Cross-platform. Supporting Windows, Mac OS X and Linux.
  • Safe. By checking potential conflicts and errors.
  • File filtering. Supporting including and excluding files via regular expression. No need to run commands like find ./ -name "*.html" -exec CMD.
  • Renaming submatch with corresponding value via key-value file.
  • Renaming via ascending integer.
  • Recursively renaming both files and directories.
  • Supporting dry run.
  • Colorful output.

Command:

$ brename -f .png -p image
[INFO] checking: [ ok ] 'image0001.png' -> '0001.png'
[INFO] checking: [ ok ] 'image0002.png' -> '0002.png'
[INFO] checking: [ ok ] 'image0003.png' -> '0003.png'
[INFO] 3 path(s) to be renamed
[INFO] renamed: 'image0001.png' -> '0001.png'
[INFO] renamed: 'image0002.png' -> '0002.png'
[INFO] renamed: 'image0003.png' -> '0003.png'
[INFO] 3 path(s) renamed
1

For Windows and linux, this Perl script will do; in this case:

$ rnm -l 's/^image//' '*.png'

The script could run recursively under directories and even prepending a count to all of them:

$ rnm -r 's/^/$counter./' '/\.png$/'

UTF-8 chars are also correctly treated, both in Windows and linux.

circulosmeos
  • 281
  • 1
  • 4
  • 4
  • rnm was already suggested in 2015 in a separate answer. – Stéphane Chazelas Dec 02 '22 at 15:04
  • That's curious: I didn't know about that tool, it's different from the one proposed here: this one has no dependencies, no compilation, and runs on Windows and Linux. Also, I give an example on how to prepend a counter which the other example lacks (I think that other one could do that also but the documentation is fairly big) – circulosmeos Dec 02 '22 at 15:54
1

Strangely, no one mentioned this well covered approach:

find . | grep \.png$ | sed 'p;s/image//' | xargs -n2 mv

And if you like playing around with arguments:

find . | grep \.png$ | sed "p;s/image//" | xargs -n2 sh -c 'echo $1 $2' $0

Single quotes after sh -c matter

Nick Roz
  • 165
  • Quite a few issues: (1) filenames can be made of several lines so can't be processed line-wise (2) you're not quoting that backslash or $. Should be grep '\.png$'. (3) s/image// removes the first image in the path, so for a ./my-images/image0001.png that would try and do mv ./my-images/image0001.png ./my-s/image0001.png and fail. You'd want to process the list depth first and only do the rename on the basename. – Stéphane Chazelas Dec 02 '22 at 15:02
  • (continued) (4) xargs expects the words on input in a very specific format, which sed is not providing here. For instance, if the file paths contain quotes or blanks or backslash, that will fail. (5), echo can't be used for arbitrary data. (6), there are missing quotes around the $0, $1,$2. – Stéphane Chazelas Dec 02 '22 at 15:03
  • @StéphaneChazelas feel free to edit my answer if you are willing to; my answer does not cover all the depth-in and many other things, it directly answers the question about one directory containing batch of images; from my perspective this rather simple solution – Nick Roz Dec 05 '22 at 11:51
  • Because of the missing quotes, this \. doesn’t do what you think it does: echo \. prints ., without the backslash. Also, why waste resources piping find into grep when you can use -name? – bfontaine Mar 11 '24 at 17:54
0

You can use this tool: rnm (web page)

For your case the command would be:

rnm -rs '/^image//' *.png

You can find more examples/docs here.

Jahid
  • 245