85

Possible Duplicate:
rename multiple files at once in unix

I would like to rename all files from a folder using a regex (add a name to the end of name) and move to another folder.

It my opinion, it should be looking like this:

mv -v ./images/*.png ./test/*test.png

but it does not work.

Can anyone suggest me a solution?

Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
mxg
  • 20,946
  • 12
  • 59
  • 80
  • 2
    Essentially the same as many other questions - such as SO 1086502 (http://stackoverflow.com/questions/1086502/). There was one asked yesterday, even. – Jonathan Leffler Dec 25 '09 at 15:14
  • I disagree that this is a duplicate per se. I wanted to use a *regex capture*, as I had filenames like `blah_blah_15_blah_blah_948ABCD.txt` and the important part for me was the first number, whereas the second number was some kind of checksum. The capture is shown at https://stackoverflow.com/a/1961273/1168342 – Fuhrmanator Sep 20 '20 at 17:00

4 Answers4

134

If you are on a linux, check special rename command which would do just that - renaming using regular expressions.

rename 's/^images\/(.+)/test\/$1.png/s' images/*.png

Otherwise, write a bash cycle over the filenames as catwalk suggested.

Community
  • 1
  • 1
kibitzer
  • 4,479
  • 1
  • 21
  • 20
  • 7
    It may be called `prename` on some systems. – Dennis Williamson Dec 25 '09 at 15:01
  • 11
    much less to remember / type, thanks! `rename 's/_20/ /g' *.mp4` – ptim Dec 30 '14 at 13:42
  • 1
    The best, simplest way to do it. Although the answer might be edited to give some examples like memeLab did. – Memke Oct 13 '15 at 12:25
  • 4
    also available on mac via homebrew `brew install rename` – Jeff Puckett Sep 10 '18 at 02:48
  • 2
    I got here because I wanted to use a capture `$1` in the destination name, to rename files like `blah_blah_15_blah_blah_948ABCD1.txt` to `15.txt` via `'s/blah_blah(\d\d)blah_blah([0-9A-F]{8})/$1/'` – Fuhrmanator Sep 20 '20 at 17:05
  • 1
    If you have to rename a lot of files (happened in my case) it's better to use `find ... -type f ... | xargs rename 's/-//g'` - otherwise you may get "Argument list too long" – Thomas Mueller May 20 '21 at 08:20
  • To be clear, it's the `rename` from [pstray](https://github.com/pstray/rename), not [util-linux](https://github.com/util-linux/util-linux). Many systems have the latter installed by default, but not the former. This got me confused for a few minutes into thinking that it's some kind of weirdly under-documented tool. – what the Jul 23 '23 at 11:48
70

Try this:

for x in *.png;do mv $x test/${x%.png}test.png;done
catwalk
  • 6,340
  • 25
  • 16
  • here's what it returns: usage: mv [-f | -i | -n] [-v] source target mv [-f | -i | -n] [-v] source ... directory – mxg Dec 25 '09 at 15:01
  • @mxg: sorry, I did not give 100% correct command: you need `cd images` first and prepend `test/` with `..` – catwalk Dec 25 '09 at 15:05
  • 5
    You should put quotes around the variable names in case there are spaces in the filenames: `for x in *.png; do mv "$x" "test/${x%.png}test.png"; done` – Dennis Williamson Dec 25 '09 at 15:05
  • It works, but it leaves one file in the folder. @catwalk, you're not paid to give solutions, but 'paid' to give good indications:) Thanks! – mxg Dec 25 '09 at 17:35
  • 8
    actually, if the filenames contain spaces, you're screwed with `for` with or without quotes. that's why it's better to use the *generator | while read line; do something with "$line"; done* idiom. in this case: `ls | grep '\.png$' | while read x; do ... ; done` – just somebody Dec 25 '09 at 19:04
  • It is very useful for me now! – mxg Feb 04 '10 at 14:39
  • 2
    @justsomebody: simply use IFS=$'\n'; in front of your line then – MensSana Sep 23 '13 at 20:21
  • 6
    Isn't that using globs and not regex? – Kieveli Jul 16 '14 at 14:39
  • @menssana: if you "simply" set `IFS` it would be good to set it back to whatever it was beforehand for the sake of the next commands that might use that mechanism. – Michał Lepczyński Mar 18 '21 at 11:20
57
$ for old in ./images*.png; do
    new=$(echo $old | sed -e 's/\.png$/test.png/')
    mv -v "$old" "$new"
  done
Greg Bacon
  • 134,834
  • 32
  • 188
  • 245
  • 3
    I like the use of sed since it allows me to replace this with whatever I like. in my case replace "%20" with " ". I used the 'g' at the end of the regex to allow that: for old in *.pdf; do new=$( echo $old | sed -e 's/\%20/ /g'); mv $old "$new";done – Marlon Jul 08 '13 at 17:20
  • 2
    Thanks! I derived the one-liner `mv file_20name.mp4 "$(echo file_20name.mp4 | sed -e 's/_20/ /g')"` from this – ptim Dec 30 '14 at 13:37
  • 1
    beautiful as this allows full power of sed regex syntax. Great combination of commands, and good prototype for many other bash scripts. – Paul Mar 24 '16 at 13:14
  • 1
    This worked beautifully for what I needed (removing underscores from file names). `for old in \`ls\`; do new=$(echo $old | sed -e 's/_//g'); mv "$old" "$new"; done` – Sean the Bean Apr 22 '16 at 15:23
  • I looked at the docs for `-e` flags but don't understand what it does – Daniel Kobe Sep 08 '16 at 20:52
  • I think this is beautiful combination of sed and other bash programs. – derek Jun 27 '23 at 06:14
5

Yet another solution would be a tool called mmv:

mmv "./images/*.png" "./test/#1test.png"
Yves M.
  • 29,855
  • 23
  • 108
  • 144
koeckera
  • 51
  • 1