LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (http://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Find image files and copy it to a common directory failed (http://www.linuxquestions.org/questions/linux-newbie-8/find-image-files-and-copy-it-to-a-common-directory-failed-937380/)

matrix13 03-31-2012 05:14 AM

Find image files and copy it to a common directory failed
 
I am using ubuntu 11.10.

I have a directory containing lot a directories and many of these directories contain several image files, both in jpg and png formats. Some directories are empty also. There might be a total of 100 files. I am trying to copy all these image files and put it in a common directory. I used the following command.

Code:

find /my/source/directory/ -iname *.jpg -exec cp {} /my/destination/directory/ \;
But this didn't copy all the files of type jpg. It only copied 6 files to be exact. So, what modification should be done in the command to copy all the files.

Also, what should I do if I want to copy both *.jpg and *.png in one go.

Thanks.

kbp 03-31-2012 05:25 AM

Maybe you don't have permissions in some of the directories .. ?

Code:

find /my/source/directory/ \( -iname *.jpg -o -iname *.png \) -exec cp {} /my/destination/directory/ \;

catkin 03-31-2012 05:37 AM

Were there any error messages? If so, what were they.

To copy (or not!) .png files too:
Code:

find /my/source/directory/ -iname *.jpg -o -iname *.png -exec cp {} /my/destination/directory/ \;
EDIT: but safer to quote the patterns to ensure bash doesn't expand them to match any .jpg or .png files in the current directory:
Code:

find /my/source/directory/ -iname '*.jpg" -o -iname '*.png' -exec cp {} /my/destination/directory/ \;

kbp 03-31-2012 05:46 AM

I did the same as you catkin but it actually needs parentheses :)

jschiwal 03-31-2012 06:12 AM

You need to quote arguments that use wildcards. Otherwise they will expand to what *.jpg or *.png files are in the current directory, before the command is run.
Code:

set find ./ -iname *.pdf
:~/Documents/pdfs> echo ${*}
find ./ -iname 7007887b.pdf  AIMagzine-DeepQA.pdf at.pdf avr-libc-user-manual-1.0.4.pdf BLUEBOOK.pdf Converting movies to .mp4 with VLC media player.pdf credentials.pdf manual3.pdf


matrix13 03-31-2012 06:32 AM

Thank you all for the explanations.

I tried with quotes also. Still not working. I am only able to copy a few files.

@kbp: I do have permission in all the directories. I even did a chmod on the parent directory. If I do the first part only, that is the "find" part, the terminal will list all the 100 and odd jpg files I have in the parent directory. But, copying them is simply not working.

@catkin:There were no error messages.

One more thing. Suppose I have a folder called 'night' and it contains 5 jpg files. When I try to run the same command on this directory, it will find and then copy all the jpg files to the destination directory. But, when I do the operation on the parent directory, as I said earlier, it is not even copying the files inside 'night' to the destination directory.

jschiwal 03-31-2012 06:40 AM

Run the command without the -exec part and see what find finds. One possibility is that the filenames contain "evil" characters, so the cp command fails.

Often -print0 is used in the find command, and the results are piped to xargs with the -0 option. This uses NULL to separate the filenames.

Code:

find /source/directory -iname "*.jpg" -o -iname "*.png" -print0 | xargs -0 cp -t /target/directory
Also look at xargs options to limit the number of arguments handled at one time. A command like "cp /source/*.jpg /target/dir/" could fail when the shell expands the * wildcard. You can run out of memory.

Another use of xargs is to add arguments from a file.
Code:

tr '\n' '\0' <filelist | xargs -0 -L 500 cp -t /target/dir

catkin 03-31-2012 06:42 AM

Quote:

Originally Posted by kbp (Post 4641288)
I did the same as you catkin but it actually needs parentheses :)

Thanks kbp but I tested and it seemed OK without:
Code:

c@CW8:~/d$ find . -iname *.jpg -o -iname *.png 2>/dev/null | grep --count '.png'
1532
c@CW8:~/d$ find . -iname *.jpg -o -iname *.png 2>/dev/null | grep --count '.jpg'
6903
c@CW8:~/d$ find --version
find (GNU findutils) 4.4.2
[snip]

Different versions of find?

jschiwal 03-31-2012 06:46 AM

Quote:

Originally Posted by matrix13 (Post 4641317)
Thank you all for the explanations.

@catkin:There were no error messages.

One more thing. Suppose I have a folder called 'night' and it contains 5 jpg files. When I try to run the same command on this directory, it will find and then copy all the jpg files to the destination directory. But, when I do the operation on the parent directory, as I said earlier, it is not even copying the files inside 'night' to the destination directory.

This sounds like you still are not quoting the arguments to -iname. You also need single quotes around '{}' to handle files with spaces.

Code:

find sourcedir/ -iname "*.jpg" -o -iname "*.png" -exec cp '{}' target/dir/ \;
Another way of handling filenames with evil characters is to feed the filelist to xargs, using the -print0 option to separate each name with a NULL.

Code:

find sourcedir/ -iname "*.jpg" -o "*.png" -print0 | xargs -0 cp -t target/dir/
Note the parenthesis. You need them.

matrix13 03-31-2012 07:05 AM

I believe this has to do something with evil characters.
I did 'cd' to the parent directory and tried the following (as I did in my terminal)

Code:

find . -iname "*.jpg" -exec cp '{}' /home/matrix/Pictures/wall/ \;
Resulted in no error messages. But only 7 files copied.
For the record, I didn't use single quotes for {} previously.

Next one.
Code:

find . -iname "*.jpg" -print0 | xargs -0 cp ~/Pictures/wall/
Got this error message
Quote:

cp: target `./lightning/1920x1200.jpg' is not a directory
and nothing got copied.

I could not make out anything. 'lightning' is one directory inside the pwd.

@jschiwal: I did not understand this code segment
Quote:

tr '\n' '\0' <filelist | xargs -0 -L 500 cp -t /target/dir

suicidaleggroll 04-01-2012 12:04 AM

For something as simple as this, I usually just skip find and do it by hand:

Code:

cp *.jpg */*.jpg */*/*.jpg /destination/
It's usually much faster doing it this way than futzing with find and passing filenames with illegal characters through exec, etc. It's only feasible if you only have a few levels of subdirectories and a few different extensions to look for though.



Edit: and if you still want to track down the find problem, stick an "echo" in front of your cp in the -exec, eg:
Code:

find . -iname "*.jpg" -exec echo cp '{}' /home/matrix/Pictures/wall/ \;
This should print out exactly what it's trying to run in cp, which might shed some light on why the cp is failing.

catkin 04-01-2012 12:51 AM

Quote:

Originally Posted by matrix13 (Post 4641346)
For the record, I didn't use single quotes for {} previously.

You got different results with and without the single quotes around {} ?

That's intriguing. I would like to understand how/why that happens. AFAIK they would be stripped by bash before find is run. On that basis they should (!) not make any difference.

Does this command show the "evil" characters (with and without single quotes around {}):
Code:

find . -iname "*.jpg" -exec /bin/ls --quoting-style=c {} \;

jschiwal 04-01-2012 11:59 PM

The "tr" commands translates between two character sets. "tr '\n' '\0' <filelist" takes its input from filelist and translates newlines to nulls. The results are printed to stdout, which is piped into xargs.


All times are GMT -5. The time now is 11:40 PM.