2

I have a bunch of files who's filename follows the pattern 'filename.ext'. eg:

filename .ext

I would like to rename all of these to remove the space before the .ext. eg:

filename.ext

I can find them all using

find * -type f -name'* .*'

but how can I then rename all these files?

Rich
  • 945
  • 1
  • 6
  • 15

4 Answers4

4

Make a file named "renamethis.sh". Its contents should be:

#!/bin/bash
mv "$1" "$(echo $1 | sed 's/ \././')"

Set the executable bit: chmod a+x renamethis.sh. Then, run something like:

find /path/to/dir -name '* .*' -type f -print0 | xargs -0L 1 /path/to/renamethis.sh

YMMV, no warranty express or implied, etc.

FWIW, the spaces are what makes this strange; as long as you don't have other oddball characters in the files names, you're good to go with this approach. If you do, you may want to consider something like a scandir/readdir loop in Perl or PHP, but the above script is the first thing that came to mind.

BMDan
  • 7,249
  • 2
  • 23
  • 34
  • Instead of using a custom script I suggest you to use the command `rename` which comes on every major distro. Check it's man page. – hmontoliu Apr 28 '11 at 10:40
  • 2
    For "rename" to work, you'd have to have a complete list of all the extensions. So something like: `for ext in $(find /path/to/dir -name '* .*' -type f | sed 's/.* \.//;s/ .*//'); do rename " .$ext" .$ext /path/to/dir/*\ .$ext; done`. Without testing, though, not sure if `rename` is going to play nice with that glob, and it seems like a roundabout way to use a specific tool, so I think I still prefer my approach in circumstances where there's more than one extension that needs to be changed. – BMDan Apr 28 '11 at 18:23
  • I'm not sure if I understand your concerns about rename. It works exactly as your sed command. – hmontoliu Apr 28 '11 at 20:34
  • 3
    for exaple given this tree structure and several files with "any number of spaces prior to a dot extension" as follows: `mkdir -p a/deep/tree` `touch a/'foo .ext' a/deep/'bar .otherext' a/deep/tree/'x .foo'` You can find and rename all of them with rename: `find a/ -name '* .*' -exec rename -v 's/ *\././' '{}' \;'` resulting in: `a/deep/tree/x .foo renamed as a/deep/tree/x.foo` `a/deep/bar .otherext renamed as a/deep/bar.otherext` `a/foo .ext renamed as a/foo.ext` – hmontoliu Apr 28 '11 at 20:40
  • 1
    @hmontoliu I see what you did there. Neat approach! :) – BMDan Apr 28 '11 at 22:37
  • @hmontoliu 's suggestion `find / -name '* .*' -exec rename -v 's/ *\././' '{}' \;` (without the last single quote mark) does the job very neatly but I wonder why `find . -name '* .*' -exec rename -v 's/ *\././' '{}' \;` doesn't work?.. – Sadi May 20 '22 at 08:32
1

This should do it for you.

#!/bin/bash

OLDIFS=${IFS}
IFS=$'\n'

for file in `find * -type f -name '* .*'`; do
 _ext=`echo ${file} | cut -d '.' -f 2-`
 _filename=`echo ${file} | cut -d ' ' -f 1`
 mv "${file}" ${_filename}.${_ext}
done

IFS=${OLDIFS}
rfelsburg
  • 767
  • 3
  • 7
  • Thanks for your answer. However the cut command didn't find the extension correctly when there were other spaces or dots in the filename. But thanks for responding. – Rich Apr 28 '11 at 03:26
  • No problem, glad you found a solution though. His is definitely more elegant than mine. – rfelsburg Apr 28 '11 at 03:36
1

I see that you've already solved your immediate problem, but in the future you might want to consider using mmv.

Teddy
  • 5,204
  • 1
  • 23
  • 27
1

In one line:

find -depth -name '* .*' -print0 |
perl -wn0e '$orig = $_; s/\s+\././g; rename($orig, $_) or warn "$orig: $!\n"'

Highlights:

  • no problem with quoting spaces in filenames
  • no problem with filenames starting with a dash
  • fast: only two processes started in parallel
  • handles directories correctly
Arjen
  • 111
  • 2