1

I want to go through a bunch of directories and rename all files that end in _test.rb to end in _spec.rb instead. It's something I've never quite figured out how to do with bash so this time I thought I'd put some effort in to get it nailed. I've so far come up short though, my best effort is:

find spec -name "*_test.rb" -exec echo mv {} `echo {} | sed s/test/spec/` \;

NB: there's an extra echo after exec so that the command is printed instead of run while I'm testing it.

When I run it the output for each matched filename is:

mv original original

i.e. the substitution by sed has been lost. What's the trick?

opsb
  • 163
  • 2
  • 6
  • 1
    I can tell you what's wrong, but I'm not sure how to tell you to fix it: bash is immediately executing `echo {} | sed s/test/spec/`, which produces {}, then bash executes the find command. Have you checked to see whether your distribution has a good `rename` program? – DerfK Jan 25 '11 at 13:37
  • 1
    Please don't [cross-post](http://stackoverflow.com/questions/4793892/recursively-rename-files-using-find-and-sed). – Dennis Williamson Jan 25 '11 at 20:36

3 Answers3

4

Too complicated. If you have the rename command available, you could try the following:

find . -name "*_test.rb" -print0 | xargs -0 rename "s/_test/_spec/" 

This finds the relevant files, sends them to xargs which in turn uses the rename tool (which renames files according to the given perl regex).

Sven
  • 97,248
  • 13
  • 177
  • 225
  • +1 for `-print0`. Also, I'd make the regexp pattern as axplicit as possible: `"s/_test.rb$/_spec.rb/"` just to be on the safe side. – SmallClanger Jan 25 '11 at 15:34
  • note that only works if you happen to have the perl script version of rename, not the standard rename that comes with util-linux. – Phil Hollenback Jan 25 '11 at 21:35
3

If you don't have rename (it's a really short Perl script) or your rename is the more simplistic util-linux version or you simply want to know how to make your command work: you just need to send it to the shell for execution:

find spec -name "*_test.rb" -exec sh -c 'echo mv "$1" "$(echo "$1" | sed s/test.rb\$/spec.rb/)"' _ {} \;
Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
0

From the man page of util-linux's rename:

   rename '_with_long_name' '' file_with_long_name.*

will remove the substring in the filenames.

So this command works if you do not have the Perl version of rename:

find . -name "*_test.rb" -print0 | xargs -0 rename "_test..rb" "_spec/rb"