LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
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-26-2010, 02:01 AM   #1
mwesolow
LQ Newbie
 
Registered: Sep 2010
Location: Waterloo, ON
Distribution: GNU/Linux
Posts: 7

Rep: Reputation: 0
Having trouble combining a for loop with find


Hello,

I am trying to get a listing of all non-directories of the form *.h or *.C or *.cc or *.cpp, and then iterate over that collection to do some work on those files. Here is my code:

Code:
for x in find `pwd` ! -type d -name '*.h' -o -name '*.C' -o -name '*.cc' -o -name '*.cpp'
do
#some work with $x
done
I tried globbing in one string for the name, but it doesn't seem to work. Aside from that, this combination doesn't seem to work either. I would appreciate your help! Note: this is part of my solution to a programming assignment in bash scripting.
 
Old 09-26-2010, 02:11 AM   #2
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
The values of $x in this string:
Code:
for x in find `pwd` ! -type etc....
will be "find", "`pwd`", "!", "-type", etc. That is, the loop sees your command as a list of words. What you need to do is embed the command.
Code:
for x in $( find . ! -type etc....)
Also, `pwd` is completely unnecessary here. Just use . or perhaps $PWD. And unless you're using a really old shell, $(..) is recommended over `..`

Last edited by David the H.; 09-26-2010 at 02:14 AM. Reason: formatting, and fixed a goof.
 
Old 09-26-2010, 02:19 AM   #3
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Hello mwesolow. In bash that can be something like this:
Code:
while read FILEPATH; do
    # do something with $FILEPATH
done < <(exec find ! -type d -name'*.h' -o -name '*.C' -o -name '*.cc' -o -name '*.cpp')
For the find command I would also prefer:
Code:
find -not -type d -iname '*.c' -or -iname '*.h' -or -iname '*.cc' -or -iname '*.cpp' -or -iname '*.hpp'

Last edited by konsolebox; 09-26-2010 at 02:20 AM.
 
Old 09-26-2010, 04:02 AM   #4
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Arch + Xfce
Posts: 6,852

Rep: Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037Reputation: 2037
Either way does the same thing in the end, really, although the while-read loop seems to be much more popular for some reason. A for loop reads the input a "word" at a time, while read grabs whole lines by default.

Whichever one you use, you should first make sure that input list is being generated correctly, then ensure that the loop is processing them properly. I usually do this by simply echoing the variable back, like this:
Code:
while read x; do
	echo "$x" | cat -A
done < <( list_generating_command )   #or <file
Piping things through cat -A is useful in cases where there's a chance of unwanted trailing spaces or non-printing characters appearing in the field. It can help you to spot dos-style carriage returns when working on text files that may have been produced on a Windows machine, for example, or where tabs have been used instead of spaces.

Once you know the basic loop is working, you can replace it with the commands you want.

PS: Don't forget that find also has an -exec option, which is useful when you only have to run a single command on the files it finds.
 
Old 09-26-2010, 04:07 AM   #5
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by David the H. View Post
Either way does the same thing in the end, really, although the while-read loop seems to be much more popular for some reason.
For var in (command substitution) were popular for a very long time before until some time when some people started showing while read from pipe commands. In those days people were still conservative about anything that's not compatible with the original sh.
 
Old 09-26-2010, 04:44 AM   #6
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by mwesolow View Post
Hello,

I am trying to get a listing of all non-directories of the form *.h or *.C or *.cc or *.cpp, and then iterate over that collection to do some work on those files. Here is my code:

Code:
for x in find `pwd` ! -type d -name '*.h' -o -name '*.C' -o -name '*.cc' -o -name '*.cpp'
do
#some work with $x
done
don't do it this way. you are going to encounter error when file names have spaces. Then you will have to set provision for IFS and such. With a while read loop, you don't need to change IFS unnecessarily.
Of course, if your task is simple, using -exec of find will just do.

Code:
find ..... | while read -r file
do
  # echo do something with "$file"
done
 
Old 09-26-2010, 06:46 AM   #7
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Quote:
Originally Posted by ghostdog74 View Post
Code:
find ..... | while read -r file
do
  # echo do something with "$file"
done
In some shells the while block is placed inside a subshell so sometimes the "while read; do :; done < <()" method is better. e.g. if a data like a counter is required to be manipulated inside the loop and then also referred in the next statements after it, that data may be lost after the loop.
 
Old 09-26-2010, 06:59 AM   #8
ghostdog74
Senior Member
 
Registered: Aug 2006
Posts: 2,697
Blog Entries: 5

Rep: Reputation: 244Reputation: 244Reputation: 244
Quote:
Originally Posted by konsolebox View Post
In some shells the while block is placed inside a subshell so sometimes the "while read; do :; done < <()" method is better.
true, but its not POSIX compatible.
 
Old 09-26-2010, 07:33 AM   #9
konsolebox
Senior Member
 
Registered: Oct 2005
Distribution: Gentoo, Slackware, LFS
Posts: 2,248
Blog Entries: 8

Rep: Reputation: 235Reputation: 235Reputation: 235
Certainly and also not compatible with the original sh. It is obvious and intended to be only compatible with bash i.e. I've also said something in post #5 about people being conservative with compatibility among shells.
 
Old 09-26-2010, 11:54 AM   #10
mwesolow
LQ Newbie
 
Registered: Sep 2010
Location: Waterloo, ON
Distribution: GNU/Linux
Posts: 7

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by David the H. View Post
The values of $x in this string:
Code:
for x in find `pwd` ! -type etc....
will be "find", "`pwd`", "!", "-type", etc. That is, the loop sees your command as a list of words. What you need to do is embed the command.
Code:
for x in $( find . ! -type etc....)
Also, `pwd` is completely unnecessary here. Just use . or perhaps $PWD. And unless you're using a really old shell, $(..) is recommended over `..`
Thanks for your reply! The first tip you gave seems to work just fine. I know that $ is for de-referencing a variable, but I would have never though to use it like this. Could you explain briefly why this works?

Thanks! And thank you everyone for your kind replies, I will be sure to incorporate your comments into my test cases!

Mike
 
Old 09-26-2010, 12:04 PM   #11
mwesolow
LQ Newbie
 
Registered: Sep 2010
Location: Waterloo, ON
Distribution: GNU/Linux
Posts: 7

Original Poster
Rep: Reputation: 0
Never mind, I found out that $() is equivalent to back-ticks in the 'newer' bash shells.
 
  


Reply



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
combining find with chmod, but doesn't work... marvelade Linux - Newbie 1 03-01-2009 11:02 AM
trouble with expr inside a while loop farkus888 Linux - General 5 04-06-2007 03:19 AM
having trouble with the do while loop in program mshinska Programming 2 10-08-2005 10:18 PM
Binutils 2.14 loop trouble EPM_Students Linux From Scratch 6 01-02-2005 11:30 PM
Binutils 2.14 loop trouble (different issue) VillageIdiot Linux From Scratch 5 12-26-2004 03:41 PM

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

All times are GMT -5. The time now is 06:29 PM.

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
Open Source Consulting | Domain Registration