1

Following this questionn Recursively rename files using find and sed I found by myself this solution to rename files using find, but I can not fully understand the last part

find . -name '*_test.rb' -exec bash -c 'echo mv $1 ${1/test.rb/spec.rb}' _ {} \;

Can anyone explain the meaning of characters '_ {}',? I guess that is some sort arguments mapping from enviroments, but ...

Some clarification will be welcome.

Community
  • 1
  • 1
csg
  • 373
  • 4
  • 9

1 Answers1

1
-exec command ;

The string `{}' is replaced by the current file name being processed. Consider the following:

% find . -type f
./file1
./file2
./file3
./file4
./file5
% find . -type f -exec sh -c 'printf "arg -> %s\n" "$0"' {} \;
arg -> ./file1
arg -> ./file2
arg -> ./file3
arg -> ./file4
arg -> ./file5

But here we execute sh -c ... for every single file found. Note also that the filename is passed to the shell as $0 (not $1).

If we wnat to optimize the code, as long as our command accepts more than one argument at a time for processing, we could use something like this:

% find . -type f -exec sh -c 'printf "arg -> %s\n" "$@"' {} +
arg -> ./file2
arg -> ./file3
arg -> ./file4
arg -> ./file5

Note the {} + syntax (vs. {} \;). From find man pages:

-exec command {} +
          This variant of the -exec action runs the specified command on the selected files, but the command line
          is built by appending each selected file name at the end; the total number of invocations of  the  com-
          mand  will  be  much less than the number of matched files.  The command line is built in much the same
          way that xargs builds its command lines.

But as you observe, the first file is missing (because $@ contains all parameters except $0). That's why we need to set our $0 by hand, in order to process all arguments correctly:

% find . -type f -exec sh -c 'printf "arg -> %s\n" "$@"' put_whatever_you_want_here {} +
arg -> ./file1
arg -> ./file2
arg -> ./file3
arg -> ./file4
arg -> ./file5

In some situations you may need to set $0 to something meaningful.

Dimitre Radoulov
  • 27,252
  • 4
  • 40
  • 48
  • Can you expand upon the reason for using $1 and not just `find . -name '*_test.rb' -exec bash -c 'echo mv $0 ${0/test.rb/spec.rb}' {} \;`, please? – agtb Oct 16 '11 at 13:23
  • Hi @agtb, for me there is no difference _in this case_. If you refer to *$0* inside the code executed by the invocation of the shell (*shell -c ...*), of course, you won't find what you expect ... – Dimitre Radoulov Oct 16 '11 at 13:31