0

Hi have the following file

 more  file.txt

 1 2 3 4 4 2
 23 4 5 23 2 3
 END_OF_LINE
 1 3 7 4 2 
 23 4 6 7 4 2 1 5 

How to print only the fields 4 and 5 and 6 from each line until the line END_OF_LINE is encountered, then, starting from that point until the end of file, print the whole line?

I have only a partial solution

 awk '{print $4" "$5" "$6}'  

Example: the desired output for the given input is:

 awk syntax ..... file.txt 
 4 4 2
 23 2 3
 END_OF_LINE
 1 3 7 4 2 
 23 4 6 7 4 2 1 5 
2

Here's what I came up with:

awk '
    /END_OF_LINE/{ matched = 1}  # When you find END_OF_LINE set the matched flag
    {
        if( matched == 0)        # If you haven't matched END_OF_LINE yet
             print $4" "$5" "$6  # ...print the required fields
        else                     # If you have already found END_OF_OLINE
             print $0            # ...print the whole line
    }' your_file

but I'm not an awk guy: I'm sure this can be better streamlined.

  • 1
    +1 Actually you did pretty well. You don't admit it but you migh as well be an awk guy. OP was asking for awk so this should be the answer. My sed reply was just a suggestion. – alvits Dec 26 '13 at 19:50
0

This is easier done in sed.

sed -n '1,/END_OF_LINE/ {s/^\([^ ]* \)\{3\}\(.*\)$/\2/p};/END_OF_LINE/,$p' file.txt
  • 1
    Why not just s/^\([^ ]* \)\{3\}//p...? – Joseph R. Dec 26 '13 at 19:12
  • Yes that will work and much simpler and easier to read. The reason I used the above is to be flexible. If the input suddenly has more than 6 entries then it is as simple as removing the '$' in the sed statement and it will still print the correct result. In fact I should have not added the $ in the first place. – alvits Dec 26 '13 at 19:38
  • Could you explain this a little please? Also, it does not seem to work, for the lines before /END_OF_LINE/, it prints all fields from the 4rd on. The OP only wants fields 4 to 6. Plus, if there are leading spaces as in the OP's example, it will treat the first space as a field and print everything from the 3rd on. – terdon Dec 27 '13 at 13:44
0

Here are a couple. The awk one is just Joseph's solution but written in a more concise way. All of these rely on the same basic idea. Just set a variable to 1 when the matched line is found and check that variable's value to decide what to print.

  1. awk

    awk '/END_OF_LINE/{ m = 1}(m==0){print $4,$5,$6; next}1;' file.txt 
    
  2. Perl

    perl -alne '$m++ if /END_OF_LINE/; $m==0? print "@F[3..5]" : print; ' file.txt 
    

    The magic is in perl's options:

    -a     turns on autosplit mode when used with a -n or -p. An implicit split command to the @F array is done as the first thing inside the implicit while loop produced by the -n or -p.

    That makes it act essentially like awk. The -n just means process an input file line by line and the -l means add a new line to each print statement (it means much more but that's what it's doing here). Finally, the -e is just a way of passing a script on the command line.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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