LinuxQuestions.org
Go Job Hunting at the LQ Job Marketplace
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-28-2012, 06:59 AM   #1
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Rep: Reputation: Disabled
Unhappy Bash- grep and loops


Hello all, I am in week two of learning Bash and I am lost!
My first task is to search the current directory for files with the extensions .c and .cc, and search for the strings printf and fprintf within those files. IF the print statements are found, then I am to add in a header if it's not already there.

This is where I am at so far-- I am finding the man pages hard to understand and googling everything has become overwhelming!

Can anyone maybe just give me a few hints? My errors that I have run into so far is that I can't seem to get the right syntax when I am piping my 'ls' results to my grep in the outer for loop...so I eventually decided to work from the inside out...but now I can't seem to get the right type of arguements for my inner grep :-(

Code:
#!/bin/sh

for FILE in `ls *.cc *.c` # | egrep "printf\ | fprintf"

do
        echo $FILE;                                    #to make sure ls worked
        if [ grep -Fqx '#include <stdio.h>' "$FILE" ]  
        then
                sed '1i\
                #include <stdio.h> ' file > new_file;
                mv new_file file;
        fi
done

Last edited by calvarado777; 09-28-2012 at 07:01 AM. Reason: typo
 
Old 09-28-2012, 07:36 AM   #2
chrism01
Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Centos 6.5, Centos 5.10
Posts: 16,239

Rep: Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024Reputation: 2024
1. you should bookmark & read
http://rute.2038bug.com/index.html.gz
http://tldp.org/LDP/Bash-Beginners-G...tml/index.html
http://www.tldp.org/LDP/abs/html/

2. here's a start (NB: bash; not sh)
Code:
#!/bin/bash
for file in `find . -name '*.c' -o -name '*.cc' `
do
#       echo $file
        grep printf $file >/dev/null
        if [[ $? -eq 0 ]]
        then
                echo $file
        fi
done
FYI: http://tldp.org/LDP/abs/html/testcon...ml#DBLBRACKETS

HTH
 
Old 09-28-2012, 07:39 AM   #3
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,458

Rep: Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941
Well... here are some notes:

1. Using the ls command to build the list of items in a for loop is not a good idea. The reasons are well explained here. You can simply use filename expansion without the ls command, instead:
Code:
for FILE in *.cc *.c
do
  :
done
2. In the if/then statement if you want to test the result of a command the square brackets must be left out:
Code:
if grep -q '#include <stdio.h>' "$FILE"
then
  :
fi
Take in mind that the opening square bracket is both a shell built-in and an external command by itself and its behaviour resembles that one of the test command. You can verify by typing the following on the command line and look at the results:
Code:
type -a [
Instead when you test a command you simply put the command after the if keyword. In this case it will return an exit status that can be 0 (that means success or true) or any other number, usually 1 (that means unsuccessful or false).

3. Using sed in Linux you don't need to redirect the output to a temporary file, if you want to change the content of the original one. The option -i let you edit the file in place. Eventually you can add a suffix (near the option) so that a (safe) backup copy of the original file is created using the suffix you specified in the command line, e.g.
Code:
sed -i.bck '1\
#include <stdio.h> ' "$FILE"

Said that, your script might be something like:
Code:
#!/bin/sh

for FILE in *.cc *.c
do
    if grep -q printf "$FILE"
        if ! grep -q '#include <stdio.h>' "$FILE"
        then
            sed -i.bck '1i\
            #include <stdio.h> ' "$FILE"
        fi
    fi
done
Note the exclamation point before the command in the if statement: it is the logical NOT operator. Literally it states: if the pattern is NOT found in the file, then.... Hope this helps.

Last edited by colucix; 09-28-2012 at 07:41 AM.
 
1 members found this post helpful.
Old 09-28-2012, 11:21 AM   #5
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,431

Rep: Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878
I know it is nit picking, but as your learning I think it is valid to mention the following:

1. You have said you are learning bash, then why is it you are using the wrong interpreter?
Code:
#!/bin/sh

Should be

#!/bin/bash
This not to say your script will not work, however by calling the script with sh, which may be a symbolic link to bash, you are telling the interpreter that the
script is POSIX in nature which does mean certain advanced features from bash are not available.

2. If you really want to learn bash, I would also suggest performing the entire task in bash as opposed to calling external commands like grep and sed.

Admittedly the code will be longer but you will learn much more about bash if you force yourself to keep external command out of it.

Just my 2 cents of course
 
Old 09-28-2012, 01:44 PM   #6
calvarado777
LQ Newbie
 
Registered: Sep 2012
Posts: 20

Original Poster
Rep: Reputation: Disabled
Talking Thank you!

You guys are fantastic! Thanks so much for the reference material too! I am in love with the pitfalls page...

I also just read grail's comment-- so we are shell scripting using bash...and I this is what I understood from that lecture..please correct my wrong assumptions...

Bash is just a variance of shell-- so when I wrote #!/bin/sh I thought that was telling the Bash shell that this file is a shell script ... is that not right?

This is the code that ended up working out for me:

Code:
#!/bin/sh

for FILE in *.cc *.c
do
        if grep -q "printf\|fprintf" "$FILE"
        then
                if ! grep -q '#include <stdio.h>' "$FILE"
                then
                        sed -i.bck '1i\#include <stdio> ' "$FILE"
                fi
        fi

done

Last edited by calvarado777; 09-28-2012 at 01:49 PM. Reason: typo
 
Old 09-28-2012, 02:39 PM   #7
grail
Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 7,431

Rep: Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878Reputation: 1878
Quote:
Bash is just a variance of shell-- so when I wrote #!/bin/sh I thought that was telling the Bash shell that this file is a shell script ... is that not right?
Yes bash is a variance just as is csh or ksh, however sh is in reference to the original Bourne Shell where as bash is GNU Bourne-Again SHell which is itself derived from sh.

As you look through the links you have been provided you will find there are several things possible in bash that are not in sh.

Here is a link to the top of the Wooledge site which all deserves to be read at some point:

http://mywiki.wooledge.org/TitleIndex
 
Old 09-28-2012, 03:00 PM   #8
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,458

Rep: Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941
Well done! Just a comment on this line:
Code:
if grep -q "printf\|fprintf" "$FILE"
the alternate pattern is not really necessary here, since printf is a substring of fprintf. In other words, a line matches printf in both cases (be it printf or fprintf) unless you tell grep to match the whole word using the -w option. In this case you may want to be sure it matches only "printf" or "fprintf" and not - for example - "sprintf", "somethingwithprintfinside" and so on.
 
  


Reply

Tags
grep, loop


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
Bash loops verse123 Linux - Newbie 3 10-22-2011 04:25 PM
[SOLVED] bash loops not behaving timl Linux - Software 5 07-20-2011 09:12 AM
Bash Loops multiplex A/V lpn1160 Linux - General 1 02-23-2008 06:01 AM
Bash Loops UnitedWeFall Programming 8 08-21-2007 06:33 AM
bash scripting and loops phoeniks Programming 5 01-24-2005 04:00 PM


All times are GMT -5. The time now is 09:00 AM.

Main Menu
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
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration