Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Let's say I have a well-structured text file with following content(no leading line numbers):

 1 Mon Jun 9 00:11:47 CST 2014
 2 eth0      Link encap:Ethernet  HWaddr D4:BE:D9:F5:5C:0E
 3           inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
 4           inet6 addr: fe80::d6be:d9ff:fef5:5c0e/64 Scope:Link
 5           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
 6           RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
 7           TX packets:250825 errors:0 dropped:0 overruns:0 carrier:0
 8           collisions:0 txqueuelen:10000
 9           RX bytes:365792552 (348.8 MiB)  TX bytes:20648578 (19.6 MiB)
10           Interrupt:24 Memory:d6000000-d6012100
11 Tue Jun 10 05:11:47 CST 2014
12 eth1      Link encap:Ethernet  HWaddr D4:BE:D9:F5:5C:10
13           inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
14           inet6 addr: fe80::d6be:d9ff:fef5:5c10/64 Scope:Link
15           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
16           RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0
17           TX packets:1206000723 errors:0 dropped:0 overruns:0 carrier:0
18           collisions:0 txqueuelen:10000
19           RX bytes:1596108082 (1.4 GiB)  TX bytes:2960952707 (2.7 GiB)
20           Interrupt:25 Memory:d8000000-d8012100

Now what I need is to filter out line#1, #3, #6 for the eth0 section and line #11, #13, #16 for the eth1 section with the grep keyword 'eth'.

Mon Jun 9 00:11:47 CST 2014    
inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
Tue Jun 10 05:11:47 CST 2014
inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0

How can i make this?

share|improve this question
1  
When you say "filter out". Do you mean keep, and filter out everything else? –  richard Jun 10 at 11:33

5 Answers 5

This worked for me:

sed -n '/eth/{n;p;n;n;n;p;}' file
  • Search for the string eth
  • n;: skip a line, p;: print the line
  • n;n;n;: skip 3 lines and print again

Edit:

This prints the line above, the line after and the line after 3 lines:

sed -n -e '/eth/{x;1!p;g;$!n;p;n;n;n;p;D;}' -e h file

And your second question: I think you may not come around typing 20 times the n; command...

share|improve this answer
    
Thanks. This is exactly what I need. Your command can print the specific lines below the matching line. Now I'm wondering how can I print the lines above the matching line? –  user1087373 Jun 10 at 7:39
    
and one more question..what if I need to print the 20th line following the matching line. Do I have to type the 'n' 20 times in the command? –  user1087373 Jun 10 at 7:44
    
@user1087373 ask the above comment as another question or edit your question to satisfy your need. –  Avinash Raj Jun 10 at 7:47
    
@user1087373 see my edit –  chaos Jun 10 at 9:06

Try this awk command,

$ awk '$1~/^eth/ {getline; print; getline; getline; getline; print}' file
          inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
          RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
          inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
          RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0

Update:

$ awk '$1~/^eth/ {print previous; getline; print; getline; getline; getline; print}{previous=$0}' file
Mon Jun 9 00:11:47 CST 2014
           inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
           RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
Tue Jun 10 05:11:47 CST 2014
           inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
           RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0
share|improve this answer

Here's a different approach that uses Perl and gives you more flexibility for which lines you want to print:

perl -n00E '
    @eth_records= grep {/eth/} split/(?=>Mon|Tue|Wed|Thu|Fri|Sat|Sun)/;
    @lines_to_print = qw{1 3 6};
    map { $_-- } @lines_to_print;
    $sep = "-"x80;
    for(@eth_records){
        say $sep;
        say for (split/\n/)[ @lines_to_print ];
        say $sep
    }' your_file

This splits the file into records at lines starting with a day's name and prints the 1st 3rd and 6th lines of all records matching /eth/

Note that it will load your whole file into memory so avoid it if your file is large.

share|improve this answer

There are several ways. Please have a look at following questions on SO:

share|improve this answer
2  
Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference. –  slm Jun 10 at 7:39
    
Thx for the info. These 2 posts are pretty good. But they don't solve my question fully –  user1087373 Jun 10 at 7:59
    
Easy way to use is grep command i suppose.Using head and tail its very easy.Say we want 4th line after the pattern matched line grep -A 4 eth FileName| tail -1 Please note that this works only for BSD or GNU grep –  Tingrammer Jun 10 at 10:12
    
One more solution is to use bash scripting. Getting the line numbers to a variable, then printing using sed.If the number of occurrence is more then according it should be programmed. num=$( grep -c eth fileName | head -1 ); sed -n '${num}p' fileName If the number of occurrence is more then, put these line numbers in array and print these lines using sed one after the other. –  Tingrammer Jun 10 at 10:22

Here are a few suggestions:

  • grep

    grep -P 'CST|inet |RX p' file
    

    This will print all lines that contain CST or inet followed by a space or RX pa. The -P activates Perl Compatible Regular Expressions which lets us use | as a logical OR. You could also achieve the same thing with either of

    grep -E 'CST|inet |RX p' file
    

    or

    grep  'CST\|inet \|RX p' file
    
  • sed

    sed -n '/CST\|inet \|RX p/p' file
    sed -rn '/CST|inet |RX p/p' file
    

    Same idea as above, the -n suppresses printing of any lines and the //p means print those lines that matched the pattern.

  • perl

    You can use the same approach in Perl:

     perl -ne 'print if /CST|inet |RX p/' file
    

    Or you could do something like

     perl -ne '$k=1 if /CST/; print if $k==1||$k==3||$k==6; $k++' file
    

    Here, the variable $k is set to 1 if the line matches CST and is incremented by one after each line is read. The line is then printed if $k has a value of 1,3 or 6. This is a more extensible approach.

    An alternative, assuming you know the line numbers you want to print, would be to simply print them directly ($. is the current line number):

    perl -ne 'print if $.==1||$.==3||$.==6||$.==11||$.==13||$.==16' file
    

    or, more idiomatically:

    perl -ne '@d=(1,3,6,11,13,16); print if $.~~@d' file
    

    Finally, you can also load the entire file into memory and print only the lines you care about:

    perl -e '@F=<>; print @F[0,2,5,10,12,15]' file
    
  • awk

    You can use the same basic approaches in awk where NR is the current line number:

    awk '/CST|inet |RX p/' file
    

    or

    awk '{if(/CST/){k=1} if(k==1||k==3||k==6){print} k++;}' file
    

    or

    awk 'NR==1||NR==3||NR==6||NR==11||NR==13||NR==16' file
    
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.