Tenten Ponce
Tenten Ponce

Reputation: 2506

How can I get words between the first two instance of text/pattern?

Input:

===================================
v2.0.0

Added feature 3
Added feature 4
===================================
v1.0.0

Added feature 1
Added feature 2
===================================

Output that I want:

v2.0.0

Added feature 3
Added feature 4

I tried this but it gets the first equals (=) and the LAST equals (=) while I want to get is the FIRST TWO equals (=)

Upvotes: 6

Views: 137

Answers (6)

Alex Harvey
Alex Harvey

Reputation: 15472

Arguably, a cleaner GNU sed solution:

sed -E '0,/^={35}$/d; //Q'

Or, if you are happy with the simpler regex proposed in other answers:

sed -E '0,/^=+$/d; //Q'

Further explanation:

  • The (extended, note -E) regex /^={35}$/ matches a line, like yours, that consists of exactly 35 equals signs. (The alternative regex /^=+$/ matches a line that is one or more equals signs.)

  • The command 0,/^={35}$/d selects all lines from the beginning of the file to the first occurrence of the pattern, and deletes.

  • The expression // causes a sed regex to default to the last regex that was used as part of an address or s/// command.

  • The Q command is a GNU extension, that causes sed to exit without printing.

Testing this:

# test.sh

cat > FILE <<EOF
other
text
===================================
v2.0.0

Added feature 3
Added feature 4
===================================
v1.0.0

Added feature 1
Added feature 2
===================================
EOF

gsed -E '0,/^={35}$/d; //Q' FILE

Output:

▶ bash test.sh 
v2.0.0

Added feature 3
Added feature 4

Upvotes: 1

potong
potong

Reputation: 58361

This might work for you (GNU sed):

sed -n '/^=\+$/{:a;n;//q;p;ba}' file

Use explicit printing by setting the option -n, this means lines will only be printed by a p or P command.

On encountering a line containing all = characters, fetch the next line and if this contains the same regexp then quit the file. Otherwise print the current line and repeat.

Upvotes: 1

oguz ismail
oguz ismail

Reputation: 50750

Here is another one in GNU sed:

$ sed -n '/^=\+$/,//{//!p;b};q' file
v2.0.0

Added feature 3
Added feature 4
  • /^=\+$/,// is a shorthand for /^=\+$/,/^=\+$/, it selects the lines between two lines consisting of equal signs inclusively, and the commands between following curly braces are executed for these lines,
  • //!p is a shorthand for /^=\+$/!p, it means if incoming line is not one of those which consist of only =s, print it,
  • b means go to the end of cycle (i.e pass q),
  • q is for exitting sed after printing selected lines.

The following version will work with all POSIX-compliant seds but it looks 2x more cryptic:

sed -n -e '/^=\{1,\}$/,//{//!p;b' -e '}' -e 'q' file

Note that these are not gonna work if there are two consequent all = lines in the input.

Upvotes: 3

Ed Morton
Ed Morton

Reputation: 203169

With GNU awk for multi-char RS:

$ awk -v RS='(^|\n)=+\n' 'NR==2' file
v2.0.0

Added feature 3
Added feature 4

With any other awk the equivalent would be lengthier:

$ awk '
    /^=+$/ { prt(); next }
    { rec=rec $0 ORS }
    END { prt() }
    function prt() { if (++nr==2) printf "%s", rec; rec="" }
' file
v2.0.0

Added feature 3
Added feature 4

Note that the above will work to print any number of record, not just the 2nd one, just by changing 2 to whatever record number you want printed and you can trivially add/change conditions like only printing the record if it contains some string instead of or in addition to based on the record number, e.g. to print the 17th record if it contains foo:

awk -v RS='(^|\n)=+\n' 'NR==17 && /foo/' file

Explanation: Your records are separated by === lines so set the Record Separator RS to a regexp that matches that description, then just print the record when the Number of Records (NR) reaches the number you want, i.e. 2 (because there's a null record before the first === line).

Upvotes: 3

RavinderSingh13
RavinderSingh13

Reputation: 133428

Could you please try following too.

awk '/^=/{count++;next} count>=2{exit} {print}'  Input_file

Upvotes: 3

James Brown
James Brown

Reputation: 37394

Here is one in awk:

$ awk '/^=+$/{f=!f;if(f==1)next;else if(f==0)exit}f' file
v2.0.0

Added feature 3
Added feature 4

In pretty print:

$ awk '/^=+$/ {     # at ===...
    f=!f            # flag state is flipped
    if(f==1)        # if its one (first ===...)
        next        # next record
    else if(f==0)   # if zero (second ===...)
        exit        # nothing more to do yeah
}
f' file             # print

Upvotes: 3

Related Questions