Reputation: 109
I have a text file with following content
data
void
void
void
1
2
3
end
6
7
8
9
data
void
void
void
4
5
6
end
4
5
8
9
I wanted to extract lines between strings 'data' and 'end' and have achieved it with the following awk one-liner
awk '/data/,/end/{i++} /end/{i=0} i>4' filename
The output is:
1
2
3
4
5
6
Now I wanted the number of times the data point appears to be appended before each block. Something like this:
3
1
2
3
3
4
5
6
Is it possible to achieve this by awk?
Upvotes: 2
Views: 264
Reputation: 133730
With your shown samples, please try following awk
program.
awk '
/data/,/end/{
if($0~/^[0-9]/){ count++ }
if($0~/^end/){
print (++count1>1? ORS count:count) ORS value
value=count=""
}
value=($0~/^[0-9]/?(value?value ORS:"")$0:ORS)
}
' Input_file
Explanation: Simply grabbing values between range of data
to end
as per shown samples. Then whenever line starts from digits increasing value of count variable by 1
and keep adding lines into value variable, whenever line starts from end then printing value of variable value and nullifying value and count to be re-initiated.
Upvotes: 2
Reputation: 163577
Instead of using the range /data/,/end/{i++}
you can use separate checks when entering and leaving the range and set variables keeping track of the lines that you want.
Another variation if you want to keep after 4 lines when matching data:
awk '/data/ {recording=1}
recording && !/end/ {
++lineNr; if (lineNr > 4) ary[++lines] = $0
}
/end/ {
if (lines) {
print "\n" lines "\n"
for (i = 1; i <= lines; i++) print ary[i]
}
recording = lineNr = lines = 0
}' file
Output
3
1
2
3
3
4
5
6
Upvotes: 1
Reputation: 67547
another
awk '/data/{if(d) print ""; f=1;c=0;d=RS}
f && /^[0-9]$/ {d=d RS $0; c++}
/end/{f=0; print c d}' file
3
1
2
3
3
4
5
6
Upvotes: 2
Reputation: 84607
You can do it fairly easily if you just count lines that are comprised of digits between the occurrence of data
and end
and store the values in an array indexed by the count. Then when end
is reached, output the count and then the values stored in the array before resetting the count and the flag that indicates you are between a data
and end
, e.g.
awk '
/data/ { between = 1 }
between==1 && $1~/^[[:digit:]]+$/ { a[++n] = $1 }
/end/ {
printf "\n%d\n\n", n
for (i = 1; i <= n; i++)
print a[i]
between = n = 0
}
' file
(note: if you can have two or more data
records without an end
that follows each data
record, you will need to add a test or handle that as needed. That is left to you.)
Example Use/Output
With your input in file
, you would get:
3
1
2
3
3
4
5
6
Let me know if you have further questions.
Upvotes: 3