LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This Linux forum is for members that are new to Linux.
Just starting out and have a question? If it is not in the man pages or the how-to's this is the place!

Notices


Reply
  Search this Thread
Old 09-11-2009, 11:03 AM   #31
lutusp
Member
 
Registered: Sep 2009
Distribution: Fedora
Posts: 835

Rep: Reputation: 102Reputation: 102

Quote:
Originally Posted by rjo98 View Post
How would i go about copying all .jpg or .JPG files from a folder and all its subfolders to my /usr/name/pictures folder? I'm guessing I'd have to use some sort of .[jJ][pP][gG] to get all the pictures from other examples i've seen, but really not sure how to use that in a recursive cp.
I read the discussion of the use of "xargs" in this thread, but there's an easier way that might prove less confusing:

Code:
find /netbackup/GRFIX/ | egrep -i "\.jpe?g$" | while read line; do echo $line; done
This way of processing the file names accepts spaces in the path and names. Just replace "echo $line" with whatever you want to do with the files. And it would be better to put this in a script, so it is easier to understand and modify, like this:

Code:
path="/netbackup/GRFIX"

find $path | egrep -i "\.jpe?g$" | while read line
do
   echo "do something to \"$line\" here."
done
The above definition of "path" happens to be useful on my system, you will need to change it for yours.
 
Old 09-11-2009, 11:04 AM   #32
i92guboj
Gentoo support team
 
Registered: May 2008
Location: Lucena, Córdoba (Spain)
Distribution: Gentoo
Posts: 4,073

Rep: Reputation: 384Reputation: 384Reputation: 384Reputation: 384
I don't quite understand, please, put some examples of paths that would be right and paths that would be incorrect with the current command line that you are using.
 
Old 09-11-2009, 11:09 AM   #33
i92guboj
Gentoo support team
 
Registered: May 2008
Location: Lucena, Córdoba (Spain)
Distribution: Gentoo
Posts: 4,073

Rep: Reputation: 384Reputation: 384Reputation: 384Reputation: 384
Quote:
Originally Posted by lutusp View Post
I read the discussion of the use of "xargs" in this thread, but there's an easier way that might prove less confusing:

Code:
find /netbackup/GRFIX/ | egrep -i "\.jpe?g$" | while read line; do echo $line; done
There are lots of ways of doing it, however this way has the problem of efficiency. As I said before, you will be running one mv or cp command for each file, which is far from efficient. It all depends on the number of files of course. xargs solves that.

Besides that, what's the point of egrep? The find -iname option does the same, doesn't it? No need for an extra pipe which bogs the system resources even more and creates yet more i/o.

Quote:
This way of processing the file names accepts spaces in the path and names.
It's a matter of correctly passing and quoting everything. This solution is not special in that regard.
 
Old 09-11-2009, 11:10 AM   #34
rjo98
Senior Member
 
Registered: Jun 2009
Location: US
Distribution: RHEL, CentOS
Posts: 1,697

Original Poster
Rep: Reputation: 48
OK. What i have is (with my notes in parentheses next to each folder)

/photos (this is where i want to run the command from)
/photos/04birthday2009 (want jpgs in here)
/photos/04birthday2009/1 (want jpgs in here)
/photos/04birthday2009/a (want jpgs in here)
/photos/04birthday2009/kjasfld (want jpgs in here)
/photos/05birthday2009 (don't want jpgs because its name starts with 05 not 04)
/photos/05birthday2009/1 (don't want jpgs because the name in the folder above starts with 05 not 04)
/photos/05birthday2009/ldfjla (don't want jpgs because the name in the folder above starts with 05 not 04)
/photos/05birthday2009/9999 (don't want jpgs because the name in the folder above starts with 05 not 04)
/photos/04kids2009 (want jpgs in here)
/photos/04kids2009/d (want jpgs in here)
/photos/04kids2009/4565 (want jpgs in here)
 
Old 09-11-2009, 11:17 AM   #35
i92guboj
Gentoo support team
 
Registered: May 2008
Location: Lucena, Córdoba (Spain)
Distribution: Gentoo
Posts: 4,073

Rep: Reputation: 384Reputation: 384Reputation: 384Reputation: 384
Yeah, we mixed directories with files and whatnot.

Let's take the directory part outside find. For example in a for loop. Instead of this:

Code:
find . -type f -iname '04*2009/*.jpg'
Try this (in /photos/):

Code:
for dir in 04*2009; do find "$dir" -type f -iname '*.jpg'; done
If the list of files is correct then just append the -print0 and the rest of the pipe with xargs as in the other oneliner above.
 
Old 09-11-2009, 11:21 AM   #36
rjo98
Senior Member
 
Registered: Jun 2009
Location: US
Distribution: RHEL, CentOS
Posts: 1,697

Original Poster
Rep: Reputation: 48
I think it might have worked, but the text scrolled by on the screen so fast and so much, i can't see all the results. is there a way to have it show the results in pieces so i can verify all the jpgs it got?
 
Old 09-11-2009, 11:29 AM   #37
i92guboj
Gentoo support team
 
Registered: May 2008
Location: Lucena, Córdoba (Spain)
Distribution: Gentoo
Posts: 4,073

Rep: Reputation: 384Reputation: 384Reputation: 384Reputation: 384
Quote:
Originally Posted by rjo98 View Post
I think it might have worked, but the text scrolled by on the screen so fast and so much, i can't see all the results. is there a way to have it show the results in pieces so i can verify all the jpgs it got?
Sure, pipe it into 'less', another great use of pipes.

Code:
for dir in 04*2009; do find "$dir" -type f -iname '*.jpg'; done | less
Then just use page up/down or the cursor keys. 'q' to exit, and '/' to search.
 
Old 09-11-2009, 11:34 AM   #38
rjo98
Senior Member
 
Registered: Jun 2009
Location: US
Distribution: RHEL, CentOS
Posts: 1,697

Original Poster
Rep: Reputation: 48
Cool!

and yes that worked. So now, to summarize all 3 pages, and please confirm i have all this right:

To move only .jpg .JPG etc files beneath where i'm running the command from to /new/path

find . -type f -iname \*.jpg -print0 | xargs -0 -i mv '{}' /new/path

to only do it in folders (and all their subfolders) who are one level beneath where i'm running this command from, only when the folder names (one level down from where i'm running the command from) begin with 04 then have some text then end in 2009

for dir in 04*2009; do find "$dir" -type f -iname '*.jpg' -print0 | xargs -0 -i mv '{}' /new/path; done
 
Old 09-11-2009, 11:40 AM   #39
i92guboj
Gentoo support team
 
Registered: May 2008
Location: Lucena, Córdoba (Spain)
Distribution: Gentoo
Posts: 4,073

Rep: Reputation: 384Reputation: 384Reputation: 384Reputation: 384
Code:
for dir in 04*2009; do find "$dir" -type f -iname '*.jpg' -print0 | xargs -0 -i mv '{}' /new/path; done
Almost.

Previously we have used this to produce the list:

Code:
for dir in 04*2009; do find "$dir" -type f -iname '*.jpg' -print0; done
Since this is what produces the list, this is what you need to pipe into xargs, resulting in:

Code:
for dir in 04*2009; do find "$dir" -type f -iname '*.jpg' -print0; done | xargs -0 -i mv '{}' /new/path
As you see, the pipe and xargs are *outside* the for loop, which ends with the keywords "done".
 
Old 09-11-2009, 11:44 AM   #40
rjo98
Senior Member
 
Registered: Jun 2009
Location: US
Distribution: RHEL, CentOS
Posts: 1,697

Original Poster
Rep: Reputation: 48
thanks.

ok, so the ; goes after the last command in the for loop, then the done goes after that to close/end the for loop, creating our data set. then the pipe makes xargs substitute that data set for where the '{}' is?
 
Old 09-11-2009, 11:47 AM   #41
rjo98
Senior Member
 
Registered: Jun 2009
Location: US
Distribution: RHEL, CentOS
Posts: 1,697

Original Poster
Rep: Reputation: 48
So in summary:

First i have to type bash since that's not my default shell, then...

To move only .jpg .JPG etc files beneath where i'm running the command from to /new/path

find . -type f -iname \*.jpg -print0 | xargs -0 -i mv '{}' /new/path

to only do it in folders (and all their subfolders) who are one level beneath where i'm running this command from, only when the folder names (one level down from where i'm running the command from) begin with 04 then have some text then end in 2009

for dir in 04*2009; do find "$dir" -type f -iname '*.jpg' -print0; done | xargs -0 -i mv '{}' /new/path
 
Old 09-11-2009, 11:51 AM   #42
i92guboj
Gentoo support team
 
Registered: May 2008
Location: Lucena, Córdoba (Spain)
Distribution: Gentoo
Posts: 4,073

Rep: Reputation: 384Reputation: 384Reputation: 384Reputation: 384
Quote:
Originally Posted by rjo98 View Post
thanks.

ok, so the ; goes after the last command in the for loop, then the done goes after that to close/end the for loop, creating our data set. then the pipe makes xargs substitute that data set for where the '{}' is?

Yes, basically.

The ; is a substitute for a carry return truly. You can do either of these, they are equivalent:

Code:
for i in <whatever>; do whatever; done
Code:
for in in whatever
do
  <whatever>
done
When you do the multi-line form, bash will print a '>' each time you complete a line, until the for sentence is completed and correctly closed. That's called secondary prompt, and it's the way that bash bash to tell us that the sentence has not ended. For example,

Code:
$ for i in 1 2 3
> do
> echo $i
> done
1
2
3
$
If you do this, you don't need the ; but you could use them anyway (it would be useless but will not harm).

In the same fashion, if you want to run three commands in a row (one after another) in command line you could do "cmd1; cmd2; cmd3"

Last edited by i92guboj; 09-11-2009 at 11:52 AM.
 
Old 09-11-2009, 12:05 PM   #43
rjo98
Senior Member
 
Registered: Jun 2009
Location: US
Distribution: RHEL, CentOS
Posts: 1,697

Original Poster
Rep: Reputation: 48
ok, yeah, the semicolon makes sense, feel kinda silly I didn't realize that on my own!

So i have the two lines correct in my above post, #41?
 
Old 09-11-2009, 12:17 PM   #44
i92guboj
Gentoo support team
 
Registered: May 2008
Location: Lucena, Córdoba (Spain)
Distribution: Gentoo
Posts: 4,073

Rep: Reputation: 384Reputation: 384Reputation: 384Reputation: 384
Yes. But you can use a slight improvement, a final slash at the end of the /new/path, so:

Code:
find . -type f -iname \*.jpg -print0 | xargs -0 -i mv '{}' /new/path/
The reason is simple: mv doesn't only move, it also renames files (which is basically the same in linux). If you specify a single level directory, like /path, and /path doesn't exist or is not a directory, then all the files will be renamed to /path, in succession. So, file1 will be move to a file called /path, then file2, then file2... fileN. This means that, by the time that the loop ends, mv will have created and overwritten a file called /path a lot of times, and the final contents of /path will be the contens of the last file you moved. The very bad thing about this is that the original files will be gone, forever.

What does adding a slash at the end do? Easy, it tells bash that /path/ is a directory, so mv will try to move the files inside a directory with that name. This is a security measure. This is also why these kind of loops, as root, can be very dangerous if you are not sure about what you are doing.

I have the habit of ending directory names always with a slash, that way there's no confusion.

Code:
for dir in 04*2009; do find "$dir" -type f -iname '*.jpg' -print0; done | xargs -0 -i mv '{}' /new/path/
 
Old 09-11-2009, 12:20 PM   #45
rjo98
Senior Member
 
Registered: Jun 2009
Location: US
Distribution: RHEL, CentOS
Posts: 1,697

Original Poster
Rep: Reputation: 48
Yeah, better safe than sorry. I'm reposting a summary just to keep it clean for anyone who reads this in the future.

So in summary:

First i have to type bash since that's not my default shell, then...

To move only .jpg .JPG etc files beneath where i'm running the command from to /new/path

find . -type f -iname \*.jpg -print0 | xargs -0 -i mv '{}' /new/path/

to only do it in folders (and all their subfolders) who are one level beneath where i'm running this command from, only when the folder names (one level down from where i'm running the command from) begin with 04 then have some text then end in 2009

for dir in 04*2009; do find "$dir" -type f -iname '*.jpg' -print0; done | xargs -0 -i mv '{}' /new/path/
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
copy recursively across directories stefaandk *BSD 1 11-09-2008 10:01 PM
how to copy images recursively via bash mindfriction Programming 6 12-13-2007 10:25 PM
Using cp to copy directory permissions recursively? SirTristan Linux - Newbie 3 11-25-2007 08:36 AM
trying to recursively copy jpegs DJOtaku Linux - General 10 08-26-2005 01:09 PM
recursively copy php.ini to www directories osio Programming 3 07-01-2005 04:24 AM

LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie

All times are GMT -5. The time now is 02:57 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration