Click to See Complete Forum and Search --> : piping from the "find" command.


blackbelt_jones
10-10-2007, 07:06 PM
I haven't done a lot of piping, and I'm still not too clear about the syntax. Is there a way that I can pipe the output from "find" into "cp" to get copies of all the files with a particular extension into one folder? I've got half-completed ktorrent downloads, and the .torrent files are scattered all over two hard drives and several different accounts.

blackbelt_jones
10-10-2007, 07:44 PM
I'd be very interested in an answer to this, but I solved the problem crudely but effectively by using > to save the output of

sudo find / -name *torrent -print to a text file

, and then using search and replace to create a crude script. I tacked "cp" onto the begining of each path in the output, tacked a destination directory on the end of each filename, ran it as a script, and it essentially copied each file into the directory individually 441 times.

Hey... it worked! :cool:

deathadder
10-10-2007, 07:53 PM
Have a look at the exec option
find ./ -iname '*.torrent' -exec cp {} /path/to/copy \;
{} is expanded to the file found.

xargs might be better off that -exec, but I'm not 100% sure of the syntax...
find ./ -iname '*.torrent' -xargs cp {} /path/to/copy

This might interest you...: http://www.wagoneers.com/UNIX/FIND/find-usage.html

bwkaz
10-11-2007, 07:14 PM
Yep -- I'd just use find's -exec option. Forget about xargs, since there's no portable way to have it work correctly in the face of all possible filename strings (GNU find and GNU xargs support the -print0 and -0 options, respectively, which will work. However, that's only GNU find/xargs. If that's not a problem, then perhaps xargs will be OK, but I'd rather stay away from it myself. :))

xargs takes each line of its input and treats that as a filename -- it puts it onto the end of the rest of its command line, and executes the result. (So you have to pipe the output from find into xargs.) Because it adds files to the end of the command line, I'm not sure it can even do what you need: you need to have the filenames in the middle, not the end.

But since find's -exec option takes a {} specifier for where to put (each) full filename, and since it will run the command once for each individual file (substituting the entire filename as one argument), you can tell it to "cp file1 /whatever/dir", then "cp file2 /whatever/dir", etc., etc., and everything will be fine. Basically, do exactly what deathadder posted. :)

deathadder
10-11-2007, 08:12 PM
Ah I had no idea about xargs, I'll have to remember that in the future, thanks bwkaz.

Ludootje
10-26-2007, 12:23 PM
Yep -- I'd just use find's -exec option. Forget about xargs, since there's no portable way to have it work correctly in the face of all possible filename strings (GNU find and GNU xargs support the -print0 and -0 options, respectively, which will work. However, that's only GNU find/xargs. If that's not a problem, then perhaps xargs will be OK, but I'd rather stay away from it myself. :))

[more stuff about the exact difference between xargs & -exec]

Yes, but xargs has the advantage of being faster (because of the exact reasons you mention in the part I left out).
So find / -name \*foo* -exec echo "{}" will be slower than find / -name \*foo* -print0 | xargs -0 echo

bwkaz
10-26-2007, 06:46 PM
I'm going to call "premature optimization" on that... :p

But seriously. You're probably right that running it via xargs is faster. But there are two reasons why that reason alone won't change my usage:

(a) Any time that I've used find, I didn't care if it ran 0.1% slower because of a bunch of extra forks with -exec. (OTOH, most of the time that I've used find -exec, the -exec part took much longer than the finding, so the find got dwarfed. That probably doesn't apply to everyone.)

(b) xargs still doesn't work right unless you're guaranteed to be using GNU find and GNU xargs, and you take the time to specify -print0 / -0.

So because I'm hacking stuff together quickly (my programming time being at more of a premium than the machine's execution time), I don't take the time to think about how the output is printed, or what special characters may or may not be in any of the filenames, or whatever -- I just use -exec and run whatever program on each file. ;)

Now, if I noticed that some script's find was running too slowly, I might go back and attempt xargs. But only if I knew it was find that was taking so long (and note that the first run of "find /" will take LOTS longer than the second, because lots of stuff is in the cache the second time through -- or at least it is on my machine), and only if I was prepared to put in extra up-front time to get it to run faster.

But I still contend that for most one-off uses of find, it's better to use -exec, even though it's slower, for the simple reason that you don't have to think about special characters in your filenames. :)