2

I'm trying to pipe into something that will return only the first "paragraph" or "section" separated by a blank line. I thought I could use awk or sed to get a range as per some other answers but it doesn't seem to work.

$ cat txt
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y

Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y

$ cat txt |awk '/^Package:/,/^$/'
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y

Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y

Should it not return only the first "section"? (as per: Grep starting from a fixed text, until the first blank line and https://www.unix.com/shell-programming-and-scripting/148692-awk-script-match-pattern-till-blank-line.html)

  • If I use grep -ve ^$ the blank lines get removed, so there's no special characters.
  • If I try to extract a different part, I get the parts from both "sections":

    $ cat txt |awk '/^Package:/,/^Version:/'
    Package: plasma-desktop
    Architecture: amd64
    Version: 4:5.12.9.1-0ubuntu0.1
    Package: plasma-desktop
    Architecture: amd64
    Version: 4:5.12.4-0ubuntu1
    
  • If I use sed -n '/^Package:/,/^$/p' or sed -n '/^Package:/,/^Version:/p' I get the same results as the equivalent awk.

How do I get awk or sed to stop after the first occurrence?

  • Welcome! Can you post the desired result? edit the question, don't add it in the comments. – schrodigerscatcuriosity Apr 7 at 18:15
5

This is exactly why awk has a paragraph mode:

$ awk -v RS= 'NR==1' file
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y

and to print the 2nd record is just the obvious change of NR==1 to NR==2:

$ awk -v RS= 'NR==2' file
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.4-0ubuntu1
Supported: 3y

Never use range expressions btw - they make code for trivial problems very slightly briefer than using a flag but then if your requirements change in the slightest require a complete rewrite or duplicate conditions. So any time you thing you might want to use /begin/,/end/ with sed or awk use /begin/{f=1} f{print} /end/{f=0} with awk instead and that gives you FAR more control on when/how to print the begin/end lines, etc.

| improve this answer | |
  • 1
    Brilliant solution -- I never looked closely at RS before. Small extension -- if the file is big, then NR > 2 {exit} would speed things up. – Paul_Pedant Apr 7 at 20:00
  • @Paul_Pedant thanks. The performance enhancement to print one record would be NR==1{print; exit}. – Ed Morton Apr 7 at 20:17
  • 1
    Much better than my answer, I'm keeping it only to show what was wrong with the original approach. – Quasímodo Apr 7 at 21:43
1

In /begin/,/end/, the "action flags" are turned on each time a /begin/ match is found and are turned off when /end/ match is found. The boundary lines with "begin" and "end" are also printed.

The consequences to your input are (printed lines have a comment after them on the below samples):

  • With '/^Package:/,/^$/':
    Package: plasma-desktop        #TURN ON
    Architecture: amd64            #
    Version: 4:5.12.9.1-0ubuntu0.1 #
    Supported: 3y                  #
                                   #TURN OFF
    Package: plasma-desktop        #TURN ON
    Architecture: amd64            #
    Version: 4:5.12.4-0ubuntu1     #
    Supported: 3y                  #
  • With '/^Package:/,/^Version:/':
    Package: plasma-desktop        #TURN ON
    Architecture: amd64            #
    Version: 4:5.12.9.1-0ubuntu0.1 #TURN OFF
    Supported: 3y

    Package: plasma-desktop        #TURN ON
    Architecture: amd64            #
    Version: 4:5.12.4-0ubuntu1     #TURN OFF
    Supported: 3y

To print only the paragraph starting from "Package:" you can write

sed -ne '/^$/q' -e '/^Package:/,$p' file

sed quits processing the file as soon as it finds a blank line because of /^$/q.

With awk:

awk '/^$/{exit};/^Package:/,0' file
| improve this answer | |
0

As commented by Quasímodo

/begin/,/end/ gets lines that match those regexes including the boundary lines. begin turns on the printing, and end turns off. The line right after your blank line turns on the printing again, because it also has Package: in it.

I realized I can use sed and change the /begin/ to 0 and it will start at the beginning. Since there is only one beginning it will only match once.

$ cat txt |sed -n '0,/^$/p'
Package: plasma-desktop
Architecture: amd64
Version: 4:5.12.9.1-0ubuntu0.1
Supported: 3y
| improve this answer | |

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.