469,352 Members | 1,685 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,352 developers. It's quick & easy.

switching from bash to Perl

Hi,
I recently started using bash and wrote some code to find certain IPs and related stuff in the leases files by using grep
I am trying to switch to perl. I am a bigginer and trying to learn perl by reading stuff on net.
I am getting stuck at following point
I wrote in bash
grep $IP data061009 -A 6

Now in perl I am writing
@result= grep (/$IP/, $_) in a while loop.
How do I incorporate '-A 6' part in perl
Please help.
Nov 10 '06 #1
13 3457
miller
1,089 Expert 1GB
There is no perl equivalent functionality for grep by default. But you can add it programmatically. Per the grep --help documentation.

Expand|Select|Wrap|Line Numbers
  1.   -A, --after-context=NUM   print NUM lines of trailing context
  2.  

Here is the code you want scetched out:

Expand|Select|Wrap|Line Numbers
  1. my $infile = "data061009";
  2. open(IN, "$infile") or die "open $inFile: $!";
  3. my $A = 0; # Variable to keep track of last seen.
  4. my @results = grep {/$IP/ ? $A=6 : $A-- > 0} <IN>;
  5. close(IN) or die "close $inFile: $!";
  6.  
You could also do the same thing using a for loop to make it more readable. But that gives you exactly what you want.
Nov 10 '06 #2
Hi, thanks a lot!! It really worked!! But they I have another basic question, how did it work? I mean I am trying to understand the code you sent...but with my limited knowledge of Perl ...I am not able to understand what exactly is happening there!!
I am also reading a book on Perl side by side....but honestly ....there is so much in it...and I dont know where to look for my difficulties and so on.
Is there any quick/ smart way to learn perl?
Thanks again!!
Nov 13 '06 #3
miller
1,089 Expert 1GB
I'm glad my code example worked, but I'm not going to teach you perl. That's not what the forums are for, and really wouldn't be a good use of either of our times. Here is the code that I posted to you in a more verbose form to make it more readable. The nice and bad thing about perl is that it truly gives you the ability to do things in many different ways. Some of them very compact, but definitely harder to understand for the beginner.

Expand|Select|Wrap|Line Numbers
  1. my $infile = "data061009";
  2. open(IN, "$infile") or die "open $inFile: $!";
  3.  
  4. # Dumbing Down these two lines of code:
  5. #my $A = 0; # Variable to keep track of last seen.
  6. #my @results = grep {/$IP/ ? $A=6 : $A-- > 0} <IN>;
  7.  
  8. my @results = (); # Accumulate content.
  9. my $trailing = 0;
  10.  
  11. while (my $line = <IN>) {
  12.     if ($line =~ /$IP/) {
  13.         # Match Found: Save Results, and queue for 5 more lines to save
  14.         push @results, $line;
  15.         $trailing = 5;
  16.     } elsif ($trailing > 0) {
  17.         # Trailing Content: Save Results, decrement counter by 1.
  18.         push @results, $line;
  19.         $trailing--;
  20.     }
  21. }
  22. # END Dumb Down
  23.  
  24. close(IN) or die "close $inFile: $!";
  25.  
This code should explain what is occuring logically. If you want to learn more about grep, regular expressions, the $_ variable, the ?: operator, and such, you'll just have to do more reading and scrounging for code examples. Also, a little time just playing around with code snippets always helps to learn what things do. But I learned perl the hard way, so I really don't know what else to suggest that would make the process easier for someone else.
Nov 13 '06 #4
Thanks...!
Nov 14 '06 #5
In bash I could access a part of a string by using [ : : ]
For example:
$string=bookshop;
new_string=${string:0:4)
echo $new_string

The code above would retrun
book

Is there any way I can do similar thing in Perl?
Please help.

Miller,
I have understood the ?: operator from our previous discussion. Please let me know if I am right,
1. if grep is successful, A is set to 6 , print the current line
2. if grep is not successful, decremet A , print the current line

This would print 6 lines after the line with the grep argument,
If the grep is not successful right in the start, A =1 and decrementing it would push it to 0, >0 condition not satisfied, so dont print current line.

Is that the right interpretation of the code?
Nov 15 '06 #6
miller
1,089 Expert 1GB
Is there any way I can access a part of a string in Perl?
Look at: http://perldoc.perl.org/functions/substr.html

my $A = 0;
my @results = grep {/$IP/ ? $A=6 : $A-- > 0} <IN>;
I have understood the ?: operator from our previous discussion. Please let me know if I am right,
1. if grep is successful, A is set to 6 , print the current line
2. if grep is not successful, decremet A , print the current line

This would print 6 lines after the line with the grep argument,
If the grep is not successful right in the start, A =1 and decrementing it would push it to 0, >0 condition not satisfied, so dont print current line.

Is that the right interpretation of the code?
Close, but not quite verbally correct:

1. if the pattern /$IP/ matches, then $A=6 is used as the condition for grep. The statement $A=6 sets $A to 6, and then returns true (6), so the line is added to @results.
2. if the pattern /$IP/ doesn't match, then $A-- > 0 is used as the condition for grep. The statement $A-- > 0 is treated as $A > 0 by grep, and then a decrement is done to $A after the value check. So if the pre decrement value of $A is greater than 0, that the line is also added to @results.

Again, it is a lot harder to write out what is happening in words, than it is to just write it out in perl. But thank you for trying. It sounds like you have a good grasp of what was going on there. The hardest part to understand being the operator precedence.

Warning more advanced, probably unneeded knowledge to follow

Your use of /$IP/ is probably not completely correct. I'm assuming that $IP is an ip address. So if $IP='192.168.1.1', the pattern would be /192.168.1.1/. You might notice there is a problem with the above regular expression, namely the dots (.). That catches a lot more ip address than you probably intend, like 192.168.141.255. Instead, you want the dots to be treated as literals, and there is an easy shortcut for you to do this.

Just use /\Q$IP\E/ as your pattern.

Try printing out "\Q$IP\E" to see what those escape sequences actually do. They come in handle in regular expression all the time when working with literals. You can read more about them at:

http://perldoc.perl.org/functions/quotemeta.html
http://perldoc.perl.org/perlretut.ht...racter-classes
Nov 16 '06 #7
Thanks Miller! I am kind of getting a little hang of coding in perl. I hope I improve....
I managed to use the 'substr' and it worked.
I am trying now to do the coding to get functionality equivalant to '-B' option of grep in perl. I will get back to you if I get stuck again.:-)
Thanks a lot for pointing out the posiible problems of using just /$IP/ as pattern!!!
Thanks!
Nov 16 '06 #8
miller
1,089 Expert 1GB
I am trying now to do the coding to get functionality equivalant to '-B' option of grep in perl. I will get back to you if I get stuck again.:-)
Expand|Select|Wrap|Line Numbers
  1. grep --help
  2.   -B, --before-context=NUM  print NUM lines of leading context
  3.  
That's a very good challenge. It's pretty straight forward to do that, but it won't be nearly as clean algorithmically. Good luck.
Nov 16 '06 #9
I got it!!!
I do not know how to copy paste the code from putty...so I am typing it out again here...so there might be minor typing errors...but the code worked!!
Here it is:

while (<IN>) {
push @previous3, $_;
shift @previous3 if @previous3 > 3;
@host= grep (/$hardware/, $_);
my $host = @host;

if ($host == 1) {
print @previous3;
}


What do you think?
Nov 16 '06 #10
miller
1,089 Expert 1GB
I got it!!!
I do not know how to copy paste the code from putty...so I am typing it out again here...so there might be minor typing errors...but the code worked!!
Here it is:

while (<IN>) {
push @previous3, $_;
shift @previous3 if @previous3 > 3;
@host= grep (/$hardware/, $_);
my $host = @host;

if ($host == 1) {
print @previous3;
}

What do you think?
Nice job.

Cleaning up your code to remove the needless use of grep first:

Expand|Select|Wrap|Line Numbers
  1. while (<IN>) {
  2.     push @previous3, $_;
  3.     shift @previous3 if @previous3 > 3;
  4.  
  5.     if (/$hardware/) {
  6.         print @previous3;
  7.     }
  8. }
  9.  
Now you have one flaw in your logic though. What happens if two lines in a row that match /$hardware/?
Nov 16 '06 #11
I know what you are saying. But since I know the structure of the input files I am scanning ...this problem wont come in my work. But I agree...the code is not foolproof. !
Nov 16 '06 #12
miller
1,089 Expert 1GB
I know what you are saying. But since I know the structure of the input files I am scanning ...this problem wont come in my work. But I agree...the code is not foolproof. !
Fine, if you won't fix it. I will.

Expand|Select|Wrap|Line Numbers
  1. while (<IN>) {
  2.     push @previous3, $_;
  3.     shift @previous3 if @previous3 > 3;
  4.  
  5.     if (/$hardware/) {
  6.         print @previous3;
  7.         @previous3 = (); # <--- Fool proof now :)
  8.     }
  9. }
  10.  
QED.
Nov 16 '06 #13
Cool!!
I will bug you in coming days if again get stuck.:)
Nov 16 '06 #14

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

2 posts views Thread by Dmitry | last post: by
11 posts views Thread by Magnus Jonneryd | last post: by
16 posts views Thread by John Salerno | last post: by
3 posts views Thread by suicidal pencil | last post: by
10 posts views Thread by Isaac Gouy | last post: by
1 post views Thread by CARIGAR | last post: by
1 post views Thread by Marylou17 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.