Grepping string, but include all non-blank lines following each grep match2019 Community Moderator ElectionHow can I grep a directory based on the contents of two successive lines?grep: Find all lines that contain Japanese kanjisBlank lines when executing “grep | xargs” in a “find -exec”How to use grep/awk/unix to match all lines from one file in another file, even if they are duplicatesRemove all the lines before the first line that contains a match?grep match all occurrences of multiple regular expressionsCompare two files and retrieve corresponding resultsregex and grep: match all letters in a listHow to search for a match, then a non-match on that line, but include context lines for matched line?How to `grep -v` and also exclude 'n' lines after the match?
Giving feedback to someone without sounding prejudiced
If the only attacker is removed from combat, is a creature still counted as having attacked this turn?
Do I have to take mana from my deck or hand when tapping a dual land?
Is there a distance limit for minecart tracks?
How to make a list of partial sums using forEach
Make a Bowl of Alphabet Soup
How to I force windows to use a specific version of SQLCMD?
SOQL query causes internal Salesforce error
Alignment of six matrices
Personal or impersonal in a technical resume
How to write Quadratic equation with negative coefficient
How to test the sharpness of a knife?
Animation: customize bounce interpolation
Would this string work as string?
If A is dense in Q, then it must be dense in R.
Would a primitive species be able to learn English from reading books alone?
Overlapping circles covering polygon
How do I tell my boss that I'm quitting in 15 days (a colleague left this week)
Can I cause damage to electrical appliances by unplugging them when they are turned on?
Did I make a mistake by ccing email to boss to others?
Does Doodling or Improvising on the Piano Have Any Benefits?
Is there a RAID 0 Equivalent for RAM?
How do you justify more code being written by following clean code practices?
The Digit Triangles
Grepping string, but include all non-blank lines following each grep match
2019 Community Moderator ElectionHow can I grep a directory based on the contents of two successive lines?grep: Find all lines that contain Japanese kanjisBlank lines when executing “grep | xargs” in a “find -exec”How to use grep/awk/unix to match all lines from one file in another file, even if they are duplicatesRemove all the lines before the first line that contains a match?grep match all occurrences of multiple regular expressionsCompare two files and retrieve corresponding resultsregex and grep: match all letters in a listHow to search for a match, then a non-match on that line, but include context lines for matched line?How to `grep -v` and also exclude 'n' lines after the match?
Consider the following toy example:
this is a line
this line contains FOO
this line is not blank
This line also contains FOO
Some random text
This line contains FOO too
Not blank
Also not blank
More random text
FOO!
Yet more random text
FOO!
So, I want the results of a grep for FOO, but with the extra wrinkle that lines following the matching lines should be included, as long as they are not blank, and they do not themselves contain FOO. So the matches would look as follows, with the different matches separated:
MATCH 1
this line contains FOO
this line is not blank
MATCH 2
This line also contains FOO
MATCH 3
This line contains FOO too
Not blank
Also not blank
MATCH 4
FOO!
Yet more random text
MATCH 5
FOO!
Bonus points (metaphorically speaking) for a simple single line script that can be run on the command line.
ADDENDUM: Adding a running count of the match number would be quite handy, if it is not too hard.
text-processing grep
|
show 3 more comments
Consider the following toy example:
this is a line
this line contains FOO
this line is not blank
This line also contains FOO
Some random text
This line contains FOO too
Not blank
Also not blank
More random text
FOO!
Yet more random text
FOO!
So, I want the results of a grep for FOO, but with the extra wrinkle that lines following the matching lines should be included, as long as they are not blank, and they do not themselves contain FOO. So the matches would look as follows, with the different matches separated:
MATCH 1
this line contains FOO
this line is not blank
MATCH 2
This line also contains FOO
MATCH 3
This line contains FOO too
Not blank
Also not blank
MATCH 4
FOO!
Yet more random text
MATCH 5
FOO!
Bonus points (metaphorically speaking) for a simple single line script that can be run on the command line.
ADDENDUM: Adding a running count of the match number would be quite handy, if it is not too hard.
text-processing grep
1
do you want all the Matches in one output or you want them to be ran separately ?
– Vivek Kanadiya
4 hours ago
I guess one output is fine, as long as they are clearly separated, say by a blank line.
– Faheem Mitha
4 hours ago
might not possible in one output but I can try to see in each separate output!
– Vivek Kanadiya
4 hours ago
For matches 4 & 5, the simple logic could say "I've matched (the 4th) "FOO", so I should continue printing in this matching block until I see a blank line, and so the final "FOO" is included in this block", but i see you've separated it -- because it's a separate "FOO" match. Do you require the 5th "FOO" to be printed separately?
– Jeff Schaller
4 hours ago
@JeffSchaller Yes, please separate different FOO matches.
– Faheem Mitha
4 hours ago
|
show 3 more comments
Consider the following toy example:
this is a line
this line contains FOO
this line is not blank
This line also contains FOO
Some random text
This line contains FOO too
Not blank
Also not blank
More random text
FOO!
Yet more random text
FOO!
So, I want the results of a grep for FOO, but with the extra wrinkle that lines following the matching lines should be included, as long as they are not blank, and they do not themselves contain FOO. So the matches would look as follows, with the different matches separated:
MATCH 1
this line contains FOO
this line is not blank
MATCH 2
This line also contains FOO
MATCH 3
This line contains FOO too
Not blank
Also not blank
MATCH 4
FOO!
Yet more random text
MATCH 5
FOO!
Bonus points (metaphorically speaking) for a simple single line script that can be run on the command line.
ADDENDUM: Adding a running count of the match number would be quite handy, if it is not too hard.
text-processing grep
Consider the following toy example:
this is a line
this line contains FOO
this line is not blank
This line also contains FOO
Some random text
This line contains FOO too
Not blank
Also not blank
More random text
FOO!
Yet more random text
FOO!
So, I want the results of a grep for FOO, but with the extra wrinkle that lines following the matching lines should be included, as long as they are not blank, and they do not themselves contain FOO. So the matches would look as follows, with the different matches separated:
MATCH 1
this line contains FOO
this line is not blank
MATCH 2
This line also contains FOO
MATCH 3
This line contains FOO too
Not blank
Also not blank
MATCH 4
FOO!
Yet more random text
MATCH 5
FOO!
Bonus points (metaphorically speaking) for a simple single line script that can be run on the command line.
ADDENDUM: Adding a running count of the match number would be quite handy, if it is not too hard.
text-processing grep
text-processing grep
edited 3 hours ago
Faheem Mitha
asked 4 hours ago
Faheem MithaFaheem Mitha
23.2k1884137
23.2k1884137
1
do you want all the Matches in one output or you want them to be ran separately ?
– Vivek Kanadiya
4 hours ago
I guess one output is fine, as long as they are clearly separated, say by a blank line.
– Faheem Mitha
4 hours ago
might not possible in one output but I can try to see in each separate output!
– Vivek Kanadiya
4 hours ago
For matches 4 & 5, the simple logic could say "I've matched (the 4th) "FOO", so I should continue printing in this matching block until I see a blank line, and so the final "FOO" is included in this block", but i see you've separated it -- because it's a separate "FOO" match. Do you require the 5th "FOO" to be printed separately?
– Jeff Schaller
4 hours ago
@JeffSchaller Yes, please separate different FOO matches.
– Faheem Mitha
4 hours ago
|
show 3 more comments
1
do you want all the Matches in one output or you want them to be ran separately ?
– Vivek Kanadiya
4 hours ago
I guess one output is fine, as long as they are clearly separated, say by a blank line.
– Faheem Mitha
4 hours ago
might not possible in one output but I can try to see in each separate output!
– Vivek Kanadiya
4 hours ago
For matches 4 & 5, the simple logic could say "I've matched (the 4th) "FOO", so I should continue printing in this matching block until I see a blank line, and so the final "FOO" is included in this block", but i see you've separated it -- because it's a separate "FOO" match. Do you require the 5th "FOO" to be printed separately?
– Jeff Schaller
4 hours ago
@JeffSchaller Yes, please separate different FOO matches.
– Faheem Mitha
4 hours ago
1
1
do you want all the Matches in one output or you want them to be ran separately ?
– Vivek Kanadiya
4 hours ago
do you want all the Matches in one output or you want them to be ran separately ?
– Vivek Kanadiya
4 hours ago
I guess one output is fine, as long as they are clearly separated, say by a blank line.
– Faheem Mitha
4 hours ago
I guess one output is fine, as long as they are clearly separated, say by a blank line.
– Faheem Mitha
4 hours ago
might not possible in one output but I can try to see in each separate output!
– Vivek Kanadiya
4 hours ago
might not possible in one output but I can try to see in each separate output!
– Vivek Kanadiya
4 hours ago
For matches 4 & 5, the simple logic could say "I've matched (the 4th) "FOO", so I should continue printing in this matching block until I see a blank line, and so the final "FOO" is included in this block", but i see you've separated it -- because it's a separate "FOO" match. Do you require the 5th "FOO" to be printed separately?
– Jeff Schaller
4 hours ago
For matches 4 & 5, the simple logic could say "I've matched (the 4th) "FOO", so I should continue printing in this matching block until I see a blank line, and so the final "FOO" is included in this block", but i see you've separated it -- because it's a separate "FOO" match. Do you require the 5th "FOO" to be printed separately?
– Jeff Schaller
4 hours ago
@JeffSchaller Yes, please separate different FOO matches.
– Faheem Mitha
4 hours ago
@JeffSchaller Yes, please separate different FOO matches.
– Faheem Mitha
4 hours ago
|
show 3 more comments
6 Answers
6
active
oldest
votes
Using awk rather than grep:
awk '/FOO/ if (matching) printf("n"); matching = 1
/^$/ if (matching) printf("n"); matching = 0
matching' file
A version that enumerates the matches:
awk 'function flush_print_maybe()
if (matching) printf("Match %dn%snn", ++n, buf)
buf = ""
/FOO/ flush_print_maybe(); matching = 1
/^$/ flush_print_maybe(); matching = 0
matching buf = (buf == "" ? $0 : buf ORS $0)
END flush_print_maybe() ' file
Both awk programs uses a very simple "state machine" to determine if it's currently matching or not matching. A match of the pattern FOO will cause it to enter the matching state, and a match of the pattern ^$ (an empty line) will cause it to enter the non-matching state.
Output of empty lines between matching sets of data happens at state transitions from matching (either into matching or into non-matching).
The first program prints any line when in the matching state.
The second program collects lines in a buf variable when in a matching state. It flushes (empties) this after possibly printing it (depending on the state), together with a Match N label at state transitions (when the first program would output an empty line).
Output of this last program on the sample data:
Match 1
this line contains FOO
this line is not blank
Match 2
This line also contains FOO
Match 3
This line contains FOO too
Not blank
Also not blank
Match 4
FOO!
Yet more random text
Match 5
FOO!
Nitpicking, these output an extra blank line if there’s a non-matching section at the end of the input ;-).
– Stephen Kitt
1 hour ago
@StephenKitt Yes. It will. Each result block will be terminated by an empty line.
– Kusalananda
1 hour ago
Only if there’s an empty line following the result block (so the example text in the question doesn’t cause an empty line to be printed at the end).
– Stephen Kitt
1 hour ago
@StephenKitt It's almost midnight here, I'll get back to it later. :-)
– Kusalananda
1 hour ago
add a comment |
I don’t think this is doable with grep, but it is with AWK:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (notfirst) print ""
notfirst = 1
/^$/
matched = 0
matched
With a count of matches:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (matches) print ""
printf "Match %dn", ++matches
/^$/
matched = 0
matched
add a comment |
sed -ne '/FOO/x;P;x;/FOO/,/^$/p' testfile
Each block of non-empty lines in the output is a single chunk of matched data from the input. The number of newlines varies.
This
- suppresses output (
-n); then - prints a blank line before every occurrence of "FOO" (
/FOO/x;P;x- uses the empty hold space); - selects ranges of lines starting from ones containing FOO (
/FOO/) and ending on empty lines (/^$/); and finally - prints those lines (
p).
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
add a comment |
I've included a pcregrep solution and a python solution.
Multiline Grep Solution
If you have pcregrep installed, you could use a multiline pattern, such as ^.*FOO.*$n?(^.*S.*$n?)*, e.g.:
pcregrep -M '^.*FOO.*$n?(^.*S.*$n?)*' test.txt
The subexpression ^.*FOO.*$n? will match any line containing the string FOO and the subexpression (^.*S.*$n?)* will match any number of subsequent lines that containing a non-whitespace character.
Python Solution
Here is a Python script that should do what you want:
#!/usr/bin/env python3
# -*- encoding: utf8 -*-
"""grep_follow.py
Search a text file for a pattern,
and output that pattern and the
non-empty lines which immediately follow it.
"""
import re
import sys
# Get the search pattern and the input file as command-line arguments
pattern = sys.argv[1]
input_file = sys.argv[2]
# Set a flag to determine whether or not to output the current line
print_flag = False
with open(input_file, "r") as _input_file:
# Iterate over the lines of the input file
for line in _input_file:
# Remove trailing whitespace
line = line.rstrip()
# If the line is empty, stop producing output
if not line.strip():
print_flag = False
# If the line matches the search pattern, start producing output
elif re.search(pattern, line):
print_flag = True
# If the print flag is set then output the line
if print_flag:
print(line)
You would run it like this:
$ python grep_follow.py FOO test.txt
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
add a comment |
awk '/FOO/print "===match " ++i "===" /FOO/,/^$/' file
===match 1===
this line contains FOO
this line is not blank
===match 2===
This line also contains FOO
===match 3===
This line contains FOO too
Not blank
Also not blank
===match 4===
FOO!
Yet more random text
===match 5===
FOO!
A similar variant where FOO could be easily changed to something else:
awk -vpat=FOO '$0~patprint "===match " ++i "===" $0~pat,/^$/' file
Omitting the terminating empty line from the default print is left as an exercise to the reader ;-)
add a comment |
Here's what I can get the output that is desired!
Match 1:
grep -iE "FOO|blank" toy.txt | head -2
Match 2:
grep -iE "FOO|blank" file.txt | grep also
Match 3:
grep -iE "FOO|blank" file.txt | tail -n 5 | head -n 3
Match 4:
grep -iE "FOO|text" file.txt | tail -n 2
Match 5:
grep -iE "FOO|text" file.txt | tail -n 1
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
This assumes knowledge of the contents of the file.
– Kusalananda
4 hours ago
yes this is based on knowledge of file
– Vivek Kanadiya
4 hours ago
1
@VivekKanadiya, I think the point here, as often in computing, is to automate a task so that it can be done automatically for multiple sets of data. A solution that only works for one particular input is hardly useful, instead of writing a set of commands to produce the output, we could just copy the required lines by hand. Note that the question also says, right there in the start, that the input shown is "a toy example".
– ilkkachu
3 hours ago
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f507517%2fgrepping-string-but-include-all-non-blank-lines-following-each-grep-match%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
Using awk rather than grep:
awk '/FOO/ if (matching) printf("n"); matching = 1
/^$/ if (matching) printf("n"); matching = 0
matching' file
A version that enumerates the matches:
awk 'function flush_print_maybe()
if (matching) printf("Match %dn%snn", ++n, buf)
buf = ""
/FOO/ flush_print_maybe(); matching = 1
/^$/ flush_print_maybe(); matching = 0
matching buf = (buf == "" ? $0 : buf ORS $0)
END flush_print_maybe() ' file
Both awk programs uses a very simple "state machine" to determine if it's currently matching or not matching. A match of the pattern FOO will cause it to enter the matching state, and a match of the pattern ^$ (an empty line) will cause it to enter the non-matching state.
Output of empty lines between matching sets of data happens at state transitions from matching (either into matching or into non-matching).
The first program prints any line when in the matching state.
The second program collects lines in a buf variable when in a matching state. It flushes (empties) this after possibly printing it (depending on the state), together with a Match N label at state transitions (when the first program would output an empty line).
Output of this last program on the sample data:
Match 1
this line contains FOO
this line is not blank
Match 2
This line also contains FOO
Match 3
This line contains FOO too
Not blank
Also not blank
Match 4
FOO!
Yet more random text
Match 5
FOO!
Nitpicking, these output an extra blank line if there’s a non-matching section at the end of the input ;-).
– Stephen Kitt
1 hour ago
@StephenKitt Yes. It will. Each result block will be terminated by an empty line.
– Kusalananda
1 hour ago
Only if there’s an empty line following the result block (so the example text in the question doesn’t cause an empty line to be printed at the end).
– Stephen Kitt
1 hour ago
@StephenKitt It's almost midnight here, I'll get back to it later. :-)
– Kusalananda
1 hour ago
add a comment |
Using awk rather than grep:
awk '/FOO/ if (matching) printf("n"); matching = 1
/^$/ if (matching) printf("n"); matching = 0
matching' file
A version that enumerates the matches:
awk 'function flush_print_maybe()
if (matching) printf("Match %dn%snn", ++n, buf)
buf = ""
/FOO/ flush_print_maybe(); matching = 1
/^$/ flush_print_maybe(); matching = 0
matching buf = (buf == "" ? $0 : buf ORS $0)
END flush_print_maybe() ' file
Both awk programs uses a very simple "state machine" to determine if it's currently matching or not matching. A match of the pattern FOO will cause it to enter the matching state, and a match of the pattern ^$ (an empty line) will cause it to enter the non-matching state.
Output of empty lines between matching sets of data happens at state transitions from matching (either into matching or into non-matching).
The first program prints any line when in the matching state.
The second program collects lines in a buf variable when in a matching state. It flushes (empties) this after possibly printing it (depending on the state), together with a Match N label at state transitions (when the first program would output an empty line).
Output of this last program on the sample data:
Match 1
this line contains FOO
this line is not blank
Match 2
This line also contains FOO
Match 3
This line contains FOO too
Not blank
Also not blank
Match 4
FOO!
Yet more random text
Match 5
FOO!
Nitpicking, these output an extra blank line if there’s a non-matching section at the end of the input ;-).
– Stephen Kitt
1 hour ago
@StephenKitt Yes. It will. Each result block will be terminated by an empty line.
– Kusalananda
1 hour ago
Only if there’s an empty line following the result block (so the example text in the question doesn’t cause an empty line to be printed at the end).
– Stephen Kitt
1 hour ago
@StephenKitt It's almost midnight here, I'll get back to it later. :-)
– Kusalananda
1 hour ago
add a comment |
Using awk rather than grep:
awk '/FOO/ if (matching) printf("n"); matching = 1
/^$/ if (matching) printf("n"); matching = 0
matching' file
A version that enumerates the matches:
awk 'function flush_print_maybe()
if (matching) printf("Match %dn%snn", ++n, buf)
buf = ""
/FOO/ flush_print_maybe(); matching = 1
/^$/ flush_print_maybe(); matching = 0
matching buf = (buf == "" ? $0 : buf ORS $0)
END flush_print_maybe() ' file
Both awk programs uses a very simple "state machine" to determine if it's currently matching or not matching. A match of the pattern FOO will cause it to enter the matching state, and a match of the pattern ^$ (an empty line) will cause it to enter the non-matching state.
Output of empty lines between matching sets of data happens at state transitions from matching (either into matching or into non-matching).
The first program prints any line when in the matching state.
The second program collects lines in a buf variable when in a matching state. It flushes (empties) this after possibly printing it (depending on the state), together with a Match N label at state transitions (when the first program would output an empty line).
Output of this last program on the sample data:
Match 1
this line contains FOO
this line is not blank
Match 2
This line also contains FOO
Match 3
This line contains FOO too
Not blank
Also not blank
Match 4
FOO!
Yet more random text
Match 5
FOO!
Using awk rather than grep:
awk '/FOO/ if (matching) printf("n"); matching = 1
/^$/ if (matching) printf("n"); matching = 0
matching' file
A version that enumerates the matches:
awk 'function flush_print_maybe()
if (matching) printf("Match %dn%snn", ++n, buf)
buf = ""
/FOO/ flush_print_maybe(); matching = 1
/^$/ flush_print_maybe(); matching = 0
matching buf = (buf == "" ? $0 : buf ORS $0)
END flush_print_maybe() ' file
Both awk programs uses a very simple "state machine" to determine if it's currently matching or not matching. A match of the pattern FOO will cause it to enter the matching state, and a match of the pattern ^$ (an empty line) will cause it to enter the non-matching state.
Output of empty lines between matching sets of data happens at state transitions from matching (either into matching or into non-matching).
The first program prints any line when in the matching state.
The second program collects lines in a buf variable when in a matching state. It flushes (empties) this after possibly printing it (depending on the state), together with a Match N label at state transitions (when the first program would output an empty line).
Output of this last program on the sample data:
Match 1
this line contains FOO
this line is not blank
Match 2
This line also contains FOO
Match 3
This line contains FOO too
Not blank
Also not blank
Match 4
FOO!
Yet more random text
Match 5
FOO!
edited 3 hours ago
answered 3 hours ago
KusalanandaKusalananda
136k17257426
136k17257426
Nitpicking, these output an extra blank line if there’s a non-matching section at the end of the input ;-).
– Stephen Kitt
1 hour ago
@StephenKitt Yes. It will. Each result block will be terminated by an empty line.
– Kusalananda
1 hour ago
Only if there’s an empty line following the result block (so the example text in the question doesn’t cause an empty line to be printed at the end).
– Stephen Kitt
1 hour ago
@StephenKitt It's almost midnight here, I'll get back to it later. :-)
– Kusalananda
1 hour ago
add a comment |
Nitpicking, these output an extra blank line if there’s a non-matching section at the end of the input ;-).
– Stephen Kitt
1 hour ago
@StephenKitt Yes. It will. Each result block will be terminated by an empty line.
– Kusalananda
1 hour ago
Only if there’s an empty line following the result block (so the example text in the question doesn’t cause an empty line to be printed at the end).
– Stephen Kitt
1 hour ago
@StephenKitt It's almost midnight here, I'll get back to it later. :-)
– Kusalananda
1 hour ago
Nitpicking, these output an extra blank line if there’s a non-matching section at the end of the input ;-).
– Stephen Kitt
1 hour ago
Nitpicking, these output an extra blank line if there’s a non-matching section at the end of the input ;-).
– Stephen Kitt
1 hour ago
@StephenKitt Yes. It will. Each result block will be terminated by an empty line.
– Kusalananda
1 hour ago
@StephenKitt Yes. It will. Each result block will be terminated by an empty line.
– Kusalananda
1 hour ago
Only if there’s an empty line following the result block (so the example text in the question doesn’t cause an empty line to be printed at the end).
– Stephen Kitt
1 hour ago
Only if there’s an empty line following the result block (so the example text in the question doesn’t cause an empty line to be printed at the end).
– Stephen Kitt
1 hour ago
@StephenKitt It's almost midnight here, I'll get back to it later. :-)
– Kusalananda
1 hour ago
@StephenKitt It's almost midnight here, I'll get back to it later. :-)
– Kusalananda
1 hour ago
add a comment |
I don’t think this is doable with grep, but it is with AWK:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (notfirst) print ""
notfirst = 1
/^$/
matched = 0
matched
With a count of matches:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (matches) print ""
printf "Match %dn", ++matches
/^$/
matched = 0
matched
add a comment |
I don’t think this is doable with grep, but it is with AWK:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (notfirst) print ""
notfirst = 1
/^$/
matched = 0
matched
With a count of matches:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (matches) print ""
printf "Match %dn", ++matches
/^$/
matched = 0
matched
add a comment |
I don’t think this is doable with grep, but it is with AWK:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (notfirst) print ""
notfirst = 1
/^$/
matched = 0
matched
With a count of matches:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (matches) print ""
printf "Match %dn", ++matches
/^$/
matched = 0
matched
I don’t think this is doable with grep, but it is with AWK:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (notfirst) print ""
notfirst = 1
/^$/
matched = 0
matched
With a count of matches:
#! /usr/bin/awk -f
/FOO/
matched = 1
if (matches) print ""
printf "Match %dn", ++matches
/^$/
matched = 0
matched
edited 1 hour ago
answered 4 hours ago
Stephen KittStephen Kitt
177k24402479
177k24402479
add a comment |
add a comment |
sed -ne '/FOO/x;P;x;/FOO/,/^$/p' testfile
Each block of non-empty lines in the output is a single chunk of matched data from the input. The number of newlines varies.
This
- suppresses output (
-n); then - prints a blank line before every occurrence of "FOO" (
/FOO/x;P;x- uses the empty hold space); - selects ranges of lines starting from ones containing FOO (
/FOO/) and ending on empty lines (/^$/); and finally - prints those lines (
p).
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
add a comment |
sed -ne '/FOO/x;P;x;/FOO/,/^$/p' testfile
Each block of non-empty lines in the output is a single chunk of matched data from the input. The number of newlines varies.
This
- suppresses output (
-n); then - prints a blank line before every occurrence of "FOO" (
/FOO/x;P;x- uses the empty hold space); - selects ranges of lines starting from ones containing FOO (
/FOO/) and ending on empty lines (/^$/); and finally - prints those lines (
p).
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
add a comment |
sed -ne '/FOO/x;P;x;/FOO/,/^$/p' testfile
Each block of non-empty lines in the output is a single chunk of matched data from the input. The number of newlines varies.
This
- suppresses output (
-n); then - prints a blank line before every occurrence of "FOO" (
/FOO/x;P;x- uses the empty hold space); - selects ranges of lines starting from ones containing FOO (
/FOO/) and ending on empty lines (/^$/); and finally - prints those lines (
p).
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
sed -ne '/FOO/x;P;x;/FOO/,/^$/p' testfile
Each block of non-empty lines in the output is a single chunk of matched data from the input. The number of newlines varies.
This
- suppresses output (
-n); then - prints a blank line before every occurrence of "FOO" (
/FOO/x;P;x- uses the empty hold space); - selects ranges of lines starting from ones containing FOO (
/FOO/) and ending on empty lines (/^$/); and finally - prints those lines (
p).
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
edited 3 hours ago
answered 3 hours ago
Michael HomerMichael Homer
49.9k8137175
49.9k8137175
add a comment |
add a comment |
I've included a pcregrep solution and a python solution.
Multiline Grep Solution
If you have pcregrep installed, you could use a multiline pattern, such as ^.*FOO.*$n?(^.*S.*$n?)*, e.g.:
pcregrep -M '^.*FOO.*$n?(^.*S.*$n?)*' test.txt
The subexpression ^.*FOO.*$n? will match any line containing the string FOO and the subexpression (^.*S.*$n?)* will match any number of subsequent lines that containing a non-whitespace character.
Python Solution
Here is a Python script that should do what you want:
#!/usr/bin/env python3
# -*- encoding: utf8 -*-
"""grep_follow.py
Search a text file for a pattern,
and output that pattern and the
non-empty lines which immediately follow it.
"""
import re
import sys
# Get the search pattern and the input file as command-line arguments
pattern = sys.argv[1]
input_file = sys.argv[2]
# Set a flag to determine whether or not to output the current line
print_flag = False
with open(input_file, "r") as _input_file:
# Iterate over the lines of the input file
for line in _input_file:
# Remove trailing whitespace
line = line.rstrip()
# If the line is empty, stop producing output
if not line.strip():
print_flag = False
# If the line matches the search pattern, start producing output
elif re.search(pattern, line):
print_flag = True
# If the print flag is set then output the line
if print_flag:
print(line)
You would run it like this:
$ python grep_follow.py FOO test.txt
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
add a comment |
I've included a pcregrep solution and a python solution.
Multiline Grep Solution
If you have pcregrep installed, you could use a multiline pattern, such as ^.*FOO.*$n?(^.*S.*$n?)*, e.g.:
pcregrep -M '^.*FOO.*$n?(^.*S.*$n?)*' test.txt
The subexpression ^.*FOO.*$n? will match any line containing the string FOO and the subexpression (^.*S.*$n?)* will match any number of subsequent lines that containing a non-whitespace character.
Python Solution
Here is a Python script that should do what you want:
#!/usr/bin/env python3
# -*- encoding: utf8 -*-
"""grep_follow.py
Search a text file for a pattern,
and output that pattern and the
non-empty lines which immediately follow it.
"""
import re
import sys
# Get the search pattern and the input file as command-line arguments
pattern = sys.argv[1]
input_file = sys.argv[2]
# Set a flag to determine whether or not to output the current line
print_flag = False
with open(input_file, "r") as _input_file:
# Iterate over the lines of the input file
for line in _input_file:
# Remove trailing whitespace
line = line.rstrip()
# If the line is empty, stop producing output
if not line.strip():
print_flag = False
# If the line matches the search pattern, start producing output
elif re.search(pattern, line):
print_flag = True
# If the print flag is set then output the line
if print_flag:
print(line)
You would run it like this:
$ python grep_follow.py FOO test.txt
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
add a comment |
I've included a pcregrep solution and a python solution.
Multiline Grep Solution
If you have pcregrep installed, you could use a multiline pattern, such as ^.*FOO.*$n?(^.*S.*$n?)*, e.g.:
pcregrep -M '^.*FOO.*$n?(^.*S.*$n?)*' test.txt
The subexpression ^.*FOO.*$n? will match any line containing the string FOO and the subexpression (^.*S.*$n?)* will match any number of subsequent lines that containing a non-whitespace character.
Python Solution
Here is a Python script that should do what you want:
#!/usr/bin/env python3
# -*- encoding: utf8 -*-
"""grep_follow.py
Search a text file for a pattern,
and output that pattern and the
non-empty lines which immediately follow it.
"""
import re
import sys
# Get the search pattern and the input file as command-line arguments
pattern = sys.argv[1]
input_file = sys.argv[2]
# Set a flag to determine whether or not to output the current line
print_flag = False
with open(input_file, "r") as _input_file:
# Iterate over the lines of the input file
for line in _input_file:
# Remove trailing whitespace
line = line.rstrip()
# If the line is empty, stop producing output
if not line.strip():
print_flag = False
# If the line matches the search pattern, start producing output
elif re.search(pattern, line):
print_flag = True
# If the print flag is set then output the line
if print_flag:
print(line)
You would run it like this:
$ python grep_follow.py FOO test.txt
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
I've included a pcregrep solution and a python solution.
Multiline Grep Solution
If you have pcregrep installed, you could use a multiline pattern, such as ^.*FOO.*$n?(^.*S.*$n?)*, e.g.:
pcregrep -M '^.*FOO.*$n?(^.*S.*$n?)*' test.txt
The subexpression ^.*FOO.*$n? will match any line containing the string FOO and the subexpression (^.*S.*$n?)* will match any number of subsequent lines that containing a non-whitespace character.
Python Solution
Here is a Python script that should do what you want:
#!/usr/bin/env python3
# -*- encoding: utf8 -*-
"""grep_follow.py
Search a text file for a pattern,
and output that pattern and the
non-empty lines which immediately follow it.
"""
import re
import sys
# Get the search pattern and the input file as command-line arguments
pattern = sys.argv[1]
input_file = sys.argv[2]
# Set a flag to determine whether or not to output the current line
print_flag = False
with open(input_file, "r") as _input_file:
# Iterate over the lines of the input file
for line in _input_file:
# Remove trailing whitespace
line = line.rstrip()
# If the line is empty, stop producing output
if not line.strip():
print_flag = False
# If the line matches the search pattern, start producing output
elif re.search(pattern, line):
print_flag = True
# If the print flag is set then output the line
if print_flag:
print(line)
You would run it like this:
$ python grep_follow.py FOO test.txt
this line contains FOO
this line is not blank
This line also contains FOO
This line contains FOO too
Not blank
Also not blank
FOO!
Yet more random text
FOO!
edited 3 hours ago
answered 4 hours ago
igaligal
5,9411536
5,9411536
add a comment |
add a comment |
awk '/FOO/print "===match " ++i "===" /FOO/,/^$/' file
===match 1===
this line contains FOO
this line is not blank
===match 2===
This line also contains FOO
===match 3===
This line contains FOO too
Not blank
Also not blank
===match 4===
FOO!
Yet more random text
===match 5===
FOO!
A similar variant where FOO could be easily changed to something else:
awk -vpat=FOO '$0~patprint "===match " ++i "===" $0~pat,/^$/' file
Omitting the terminating empty line from the default print is left as an exercise to the reader ;-)
add a comment |
awk '/FOO/print "===match " ++i "===" /FOO/,/^$/' file
===match 1===
this line contains FOO
this line is not blank
===match 2===
This line also contains FOO
===match 3===
This line contains FOO too
Not blank
Also not blank
===match 4===
FOO!
Yet more random text
===match 5===
FOO!
A similar variant where FOO could be easily changed to something else:
awk -vpat=FOO '$0~patprint "===match " ++i "===" $0~pat,/^$/' file
Omitting the terminating empty line from the default print is left as an exercise to the reader ;-)
add a comment |
awk '/FOO/print "===match " ++i "===" /FOO/,/^$/' file
===match 1===
this line contains FOO
this line is not blank
===match 2===
This line also contains FOO
===match 3===
This line contains FOO too
Not blank
Also not blank
===match 4===
FOO!
Yet more random text
===match 5===
FOO!
A similar variant where FOO could be easily changed to something else:
awk -vpat=FOO '$0~patprint "===match " ++i "===" $0~pat,/^$/' file
Omitting the terminating empty line from the default print is left as an exercise to the reader ;-)
awk '/FOO/print "===match " ++i "===" /FOO/,/^$/' file
===match 1===
this line contains FOO
this line is not blank
===match 2===
This line also contains FOO
===match 3===
This line contains FOO too
Not blank
Also not blank
===match 4===
FOO!
Yet more random text
===match 5===
FOO!
A similar variant where FOO could be easily changed to something else:
awk -vpat=FOO '$0~patprint "===match " ++i "===" $0~pat,/^$/' file
Omitting the terminating empty line from the default print is left as an exercise to the reader ;-)
answered 1 hour ago
mosvymosvy
8,3421732
8,3421732
add a comment |
add a comment |
Here's what I can get the output that is desired!
Match 1:
grep -iE "FOO|blank" toy.txt | head -2
Match 2:
grep -iE "FOO|blank" file.txt | grep also
Match 3:
grep -iE "FOO|blank" file.txt | tail -n 5 | head -n 3
Match 4:
grep -iE "FOO|text" file.txt | tail -n 2
Match 5:
grep -iE "FOO|text" file.txt | tail -n 1
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
This assumes knowledge of the contents of the file.
– Kusalananda
4 hours ago
yes this is based on knowledge of file
– Vivek Kanadiya
4 hours ago
1
@VivekKanadiya, I think the point here, as often in computing, is to automate a task so that it can be done automatically for multiple sets of data. A solution that only works for one particular input is hardly useful, instead of writing a set of commands to produce the output, we could just copy the required lines by hand. Note that the question also says, right there in the start, that the input shown is "a toy example".
– ilkkachu
3 hours ago
add a comment |
Here's what I can get the output that is desired!
Match 1:
grep -iE "FOO|blank" toy.txt | head -2
Match 2:
grep -iE "FOO|blank" file.txt | grep also
Match 3:
grep -iE "FOO|blank" file.txt | tail -n 5 | head -n 3
Match 4:
grep -iE "FOO|text" file.txt | tail -n 2
Match 5:
grep -iE "FOO|text" file.txt | tail -n 1
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
This assumes knowledge of the contents of the file.
– Kusalananda
4 hours ago
yes this is based on knowledge of file
– Vivek Kanadiya
4 hours ago
1
@VivekKanadiya, I think the point here, as often in computing, is to automate a task so that it can be done automatically for multiple sets of data. A solution that only works for one particular input is hardly useful, instead of writing a set of commands to produce the output, we could just copy the required lines by hand. Note that the question also says, right there in the start, that the input shown is "a toy example".
– ilkkachu
3 hours ago
add a comment |
Here's what I can get the output that is desired!
Match 1:
grep -iE "FOO|blank" toy.txt | head -2
Match 2:
grep -iE "FOO|blank" file.txt | grep also
Match 3:
grep -iE "FOO|blank" file.txt | tail -n 5 | head -n 3
Match 4:
grep -iE "FOO|text" file.txt | tail -n 2
Match 5:
grep -iE "FOO|text" file.txt | tail -n 1
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Here's what I can get the output that is desired!
Match 1:
grep -iE "FOO|blank" toy.txt | head -2
Match 2:
grep -iE "FOO|blank" file.txt | grep also
Match 3:
grep -iE "FOO|blank" file.txt | tail -n 5 | head -n 3
Match 4:
grep -iE "FOO|text" file.txt | tail -n 2
Match 5:
grep -iE "FOO|text" file.txt | tail -n 1
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
edited 4 hours ago
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
answered 4 hours ago
Vivek KanadiyaVivek Kanadiya
1797
1797
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
Vivek Kanadiya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
This assumes knowledge of the contents of the file.
– Kusalananda
4 hours ago
yes this is based on knowledge of file
– Vivek Kanadiya
4 hours ago
1
@VivekKanadiya, I think the point here, as often in computing, is to automate a task so that it can be done automatically for multiple sets of data. A solution that only works for one particular input is hardly useful, instead of writing a set of commands to produce the output, we could just copy the required lines by hand. Note that the question also says, right there in the start, that the input shown is "a toy example".
– ilkkachu
3 hours ago
add a comment |
This assumes knowledge of the contents of the file.
– Kusalananda
4 hours ago
yes this is based on knowledge of file
– Vivek Kanadiya
4 hours ago
1
@VivekKanadiya, I think the point here, as often in computing, is to automate a task so that it can be done automatically for multiple sets of data. A solution that only works for one particular input is hardly useful, instead of writing a set of commands to produce the output, we could just copy the required lines by hand. Note that the question also says, right there in the start, that the input shown is "a toy example".
– ilkkachu
3 hours ago
This assumes knowledge of the contents of the file.
– Kusalananda
4 hours ago
This assumes knowledge of the contents of the file.
– Kusalananda
4 hours ago
yes this is based on knowledge of file
– Vivek Kanadiya
4 hours ago
yes this is based on knowledge of file
– Vivek Kanadiya
4 hours ago
1
1
@VivekKanadiya, I think the point here, as often in computing, is to automate a task so that it can be done automatically for multiple sets of data. A solution that only works for one particular input is hardly useful, instead of writing a set of commands to produce the output, we could just copy the required lines by hand. Note that the question also says, right there in the start, that the input shown is "a toy example".
– ilkkachu
3 hours ago
@VivekKanadiya, I think the point here, as often in computing, is to automate a task so that it can be done automatically for multiple sets of data. A solution that only works for one particular input is hardly useful, instead of writing a set of commands to produce the output, we could just copy the required lines by hand. Note that the question also says, right there in the start, that the input shown is "a toy example".
– ilkkachu
3 hours ago
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f507517%2fgrepping-string-but-include-all-non-blank-lines-following-each-grep-match%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
do you want all the Matches in one output or you want them to be ran separately ?
– Vivek Kanadiya
4 hours ago
I guess one output is fine, as long as they are clearly separated, say by a blank line.
– Faheem Mitha
4 hours ago
might not possible in one output but I can try to see in each separate output!
– Vivek Kanadiya
4 hours ago
For matches 4 & 5, the simple logic could say "I've matched (the 4th) "FOO", so I should continue printing in this matching block until I see a blank line, and so the final "FOO" is included in this block", but i see you've separated it -- because it's a separate "FOO" match. Do you require the 5th "FOO" to be printed separately?
– Jeff Schaller
4 hours ago
@JeffSchaller Yes, please separate different FOO matches.
– Faheem Mitha
4 hours ago