I am trying to recursively loop through a directory which contains numerous other directories and files and then find all the .rb files and copy them to another directory.

This is what I have so far but it is not working quite right as it copies everything in the current directory to the specified directory and does not only print .rb (ruby) files to the directory from the directory that is recursively iterated through.

This is the BASH command I am using: ls -R metasploit-framework-master | grep .rb | cp * gems

In this command metasploit-framework-master is the top-level directory to recursively iterate through with the ls -R command. Also gems is the directory to place all the .rb ruby files in.

The first part ls -R metasploit-framework-master | grep .rb does seem to find all the ruby script source files but the last part grep .rb | cp * gems does not seem to pipe in the output of the grep command to the copy command.

Can any BASH experts please help me out? `

  • "cp * gems" does not read from stdin.
    – asjo
    Jul 6, 2014 at 15:37
  • This question has nothing to do with programming.
    – asjo
    Jul 6, 2014 at 19:04
  • @asjo this is not shell programming?
    – user3808269
    Jul 6, 2014 at 19:18
  • I wouldn't call piping output from one command into another programming, no - I think this question belongs on another of the sites.
    – asjo
    Jul 6, 2014 at 20:24

2 Answers 2


You should use find with exec, see http://en.wikipedia.org/wiki/Find#Execute_an_action . In your case, this should do it:

find metasploit-framework-master -name '*.rb' -exec cp -av {} gems \;
  • I tried this seems to work! :D Thank-you for the help. I am going to experiment with the other guys ideas/script first before voting an official answer. This is awesome though. :D !!!
    – user3808269
    Jul 6, 2014 at 15:41
  • what is the backslash at the end doing? or the brackets for that matter? 0_o
    – user3808269
    Jul 6, 2014 at 15:43
  • @user3808269 man find and also tons of good examples, -exec specifically.
    – Jason C
    Jul 6, 2014 at 15:49
  • @JasonC thanx for the helpful info I will have to check these out. :D
    – user3808269
    Jul 6, 2014 at 15:50

The easiest thing to drop in here is xargs. xargs lets you take stdin and use them as arguments in other commands. I would try something like this:

## This will not work as expected ## 
$ ls -R metasploit-framework-master | grep .rb | xargs -I{} cp {} gems

However, this really won't work as you want:

  • ls -R is not going to give you the full path.
  • grep .rb will match more than just that end with .rb and should be escaped.
  • cp {} gems will not handle spaces in the path.

The better way to do this is to use find.

$ find metasploit-framework-master -name '*.rb' | xargs -I{} cp {} gems/

will let you do the recursive enumeration you want. From there you can pipe that to xargs, or even more succinct use the -exec flag:

$ find metasploit-framework-master -name '*.rb' -exec cp {} gems/ \;
  • 1
    ls -R does not output the file path, this is not going to work.
    – Jakob
    Jul 6, 2014 at 15:35
  • @Michael Thanks, for the helpful reply. What is the brackets doing in this command (The last one) that follow the -r (recursive copy)? Also what is the backslash doing at the end and is the semi-colon actually necessary?
    – user3808269
    Jul 6, 2014 at 15:44
  • The brackets are a placeholder for where you want to fill in the argument and the \ is necessary to escape the semi-colon from the rest of the command.
    – Michael
    Jul 6, 2014 at 15:46
  • Your ls answer is flawed in many ways. Beyond the point made above by @Jakob, grep .rb will match such filenames as “carbon” and “orbital”, because the “.” isn’t escaped and the regular expression isn’t anchored with a “$”. Also, find … | xargs … has a problem with filenames that contain whitespace and/or quotes; use find … -print0 | xargs -0 … instead. Also, why did you change cp to cp -r? Jul 7, 2014 at 15:58
  • Generally speaking, yes use teh "xargs". I see people using find with exec. I still prefer using xargs. Also, when you do this, please use the "echo" command first whenever possible so you can see what will actually happen before it happens. I have started using for loops instead of pipe and xargs because it gives me a lot more control over using "echo" to see what's going to happen. A simple example would be like "for file in [your find statement]; do echo "cp $file gems/"; done" and then if you like what you see, take out the echo and then run it.
    – ben
    Jul 7, 2014 at 18:43

You must log in to answer this question.