Reputation: 2710
Is it possible to pipe the results of find
to a COPY command cp
?
Like this:
find . -iname "*.SomeExt" | cp Destination Directory
Seeking, I always find this kind of formula such as from this post:
find . -name "*.pdf" -type f -exec cp {} ./pdfsfolder \;
This raises some questions:
|
pipe? isn't that what its for?-exec
|
?Upvotes: 46
Views: 40508
Reputation: 108
If you want to preserve the directory structure of the files you are copying (which is useful if you are copying multiple files with the same name in different directories), you can use the --parents
and -t
options:
find . -iname "*.SomeExt" | xargs cp --parents -t Destination_Directory/
Upvotes: 0
Reputation: 61
Try this:
find . -iname "*.SomeExt" -print0 | xargs -0 cp -t Directory
# ........................^^^^^^^..........^^
In case there is whitespace in filenames.
Upvotes: 6
Reputation: 532
I like the spirit of the response from @fedorqui-so-stop-harming, but it needed a tweak to work in my bash terminal.
In this version...
find . -iname "*.SomeExt" | xargs cp Destination_Directory/
The cp
command incorrectly takes Destination_Directory/
as the first argument. I needed to add a replacement string in order to get xargs
to insert the argument in the right position for cp
. I used a percent symbol for the replacement string, but you can use anything that doesn't conflict with the input from the pipe. This version works for me.
find . -iname "*.SomeExt" | xargs -I % cp % Destination_Directory/
Upvotes: 2
Reputation: 129
This SOLVED my problem.
find . -type f | grep '\.pdf' | while read line
do
cp $line REPLACE_WITH_TARGET_DIRECTORY
done
Upvotes: 1
Reputation: 32
If there are spaces in the filenames, try:
find . -iname *.ext > list.txt
cat list.txt | awk 'BEGIN {a="'"'"'"}{print "cp "a$0a" Directory"}' > script.sh
sh script.sh
You can inspect list.txt
and script.sh
before sh script.sh
. Remember to delete the list.txt
and script.sh
afterwards.
I had some files with parenthesis and wanted a progress bar, so replaced the cat
line with:
cat list.txt | awk -v X='"' '{print "rsync -Pa "X$0X" /Volumes/Untitled/"}' > script.sh
Upvotes: 0
Reputation: 289825
Good question!
- why cant you just use | pipe? isn't that what its for?
You can pipe, of course, xargs
is done for these cases:
find . -iname "*.SomeExt" | xargs cp Destination_Directory/
- Why does everyone recommend the -exec
The -exec
is good because it provides more control of exactly what you are executing. Whenever you pipe there may be problems with corner cases: file names containing spaces or new lines, etc.
- how do I know when to use that (exec) over pipe | ?
It is really up to you and there can be many cases. I would use -exec
whenever the action to perform is simple. I am not a very good friend of xargs
, I tend to prefer an approach in which the find
output is provided to a while
loop, such as:
while IFS= read -r result
do
# do things with "$result"
done < <(find ...)
Upvotes: 33
Reputation: 246867
There's a little-used option for cp
: -t destination
-- see the man page:
find . -iname "*.SomeExt" | xargs cp -t Directory
Upvotes: 40
Reputation: 2337
You can use |
like below:
find . -iname "*.SomeExt" | while read line
do
cp $line DestDir/
done
Answering your questions:
|
can be used to solve this issue. But as seen above, it involves a lot of code. Moreover, |
will create two process - one for find
and another for cp
.
Instead using exec()
inside find
will solve the problem in a single process.
Upvotes: 11