How can I make grep print the lines below and above each matching line?
grep's -A 1
option will give you one line after; -B 1
will give you one line before; and -C 1
combines both to give you one line both before and after, -1
does the same.
How to grep for lines above and below a certain pattern
Use grep
with the parameters -A
and -B
to indicate the number a of lines A
fter and B
efore you want to print around your pattern:
grep -A1 -B1 yourpattern file
An
stands forn
lines "after" the match.Bm
stands form
lines "before" the match.
If both numbers are the same, just use -C
:
grep -C1 yourpattern file
Test
$ cat file
Foo line
Bar line
Baz line
hello
bye
hello
Foo1 line
Bar line
Baz1 line
Let's grep
:
$ grep -A1 -B1 Bar file
Foo line
Bar line
Baz line
--
Foo1 line
Bar line
Baz1 line
To get rid of the group separator, you can use --no-group-separator
:
$ grep --no-group-separator -A1 -B1 Bar file
Foo line
Bar line
Baz line
Foo1 line
Bar line
Baz1 line
From man grep
:
-A NUM, --after-context=NUM
Print NUM lines of trailing context after matching lines.
Places a line containing a group separator (--) between
contiguous groups of matches. With the -o or --only-matching
option, this has no effect and a warning is given.
-B NUM, --before-context=NUM
Print NUM lines of leading context before matching lines.
Places a line containing a group separator (--) between
contiguous groups of matches. With the -o or --only-matching
option, this has no effect and a warning is given.
-C NUM, -NUM, --context=NUM
Print NUM lines of output context. Places a line containing a
group separator (--) between contiguous groups of matches. With
the -o or --only-matching option, this has no effect and a
warning is given.
grep: show lines surrounding each match
For BSD or GNU grep
you can use -B num
to set how many lines before the match and -A num
for the number of lines after the match.
grep -B 3 -A 2 foo README.txt
If you want the same number of lines before and after you can use -C num
.
grep -C 3 foo README.txt
This will show 3 lines before and 3 lines after.
How do I fetch lines before/after the grep result in bash?
You can use the -B
and -A
to print lines before and after the match.
grep -i -B 10 'error' data
Will print the 10 lines before the match, including the matching line itself.
How to print both the grep pattern and the resulting matched line on the same line?
For the updated sample input and full-matching requirement and assuming you never have any regexp metacharacters in file1 and that the matching strings in file2 are never at the start or end of the line:
$ awk 'NR==FNR{strs[$0]; next} {for (str in strs) if ($0 ~ ("[^[:alnum:]]"str"[^[:alnum:]]")) print $0, str}' file1 file2
XP_033390445.1_uncharacterized_protein_BU24DRAFT_430534_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_430534
XP_033390442.1_uncharacterized_protein_BU24DRAFT_488391_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_488391
XP_033390437.1_uncharacterized_protein_BU24DRAFT_488386_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_488386
XP_033390400.1_uncharacterized_protein_BU24DRAFT_417707_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_417707
XP_033390397.1_uncharacterized_protein_BU24DRAFT_417704_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_417704
XP_033390371.1_uncharacterized_protein_BU24DRAFT_488335_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_488335
XP_033376581.1_uncharacterized_protein_BU24DRAFT_429509_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_429509
XP_033376580.1_uncharacterized_protein_BU24DRAFT_210092_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_210092
XP_033376578.1_uncharacterized_protein_BU24DRAFT_229465,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_229465
XP_033376577.1_uncharacterized_protein_BU24DRAFT_498094,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_498094
XP_033376576.1_uncharacterized_protein_BU24DRAFT_416051,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_416051
XP_033376575.1_uncharacterized_protein_BU24DRAFT_482795,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_482795
Original answer doing partial matching:
The correct approach is 1 call to awk:
$ awk 'NR==FNR{strs[$0]; next} {for (str in strs) if (index($0,str)) print $0, str}' file1 file2
XP_033376575.1_uncharacterized_protein_BU24DRAFT_482795,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_482795
XP_033376576.1_uncharacterized_protein_BU24DRAFT_416051,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_416051
XP_033376577.1_uncharacterized_protein_BU24DRAFT_498094,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_498094
XP_033376578.1_uncharacterized_protein_BU24DRAFT_229465,_partial_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_229465
XP_033376580.1_uncharacterized_protein_BU24DRAFT_210092_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_210092
XP_033376581.1_uncharacterized_protein_BU24DRAFT_429509_Aaosphaeria_arxii_CBS_175.79 BU24DRAFT_429509
See https://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice and https://mywiki.wooledge.org/Quotes for some of the issues with the script in your question.
how to show n lines above and below my grep search?
With -C
you get the context around the match:
grep -C4 -i authorization /etc/kubernetes/manifests/kube-apiserver.yaml
From grep
man page:
Context Line Control
-A NUM, --after-context=NUM
Print NUM lines of trailing context after matching lines. Places a line containing a group separator (described under --group-separator) between contiguous groups of matches.
With the -o or --only-matching option, this has no effect and a warning is given.
-B NUM, --before-context=NUM
Print NUM lines of leading context before matching lines. Places a line containing a group separator (described under --group-separator) between contiguous groups of matches.
With the -o or --only-matching option, this has no effect and a warning is given.
-C NUM, -NUM, --context=NUM
Print NUM lines of output context. Places a line containing a group separator (described under --group-separator) between contiguous groups of matches. With the -o or
--only-matching option, this has no effect and a warning is given.
How can I make 'grep' show a single line five lines above the grepped line?
OK, I think this will do what you're looking for. It will look for a pattern, and extract the 5th line before each match.
grep -B5 "pattern" filename | awk -F '\n' 'ln ~ /^$/ { ln = "matched"; print $1 } $1 ~ /^--$/ { ln = "" }'
basically how this works is it takes the first line, prints it, and then waits until it sees ^--$
(the match separator used by grep), and starts again.
Print line after the match in grep
If you want to use grep
as the tool for this, you can achieve it by adding another segment to your pipeline:
cmus-remote -Q | grep -A 1 "tag genre" | grep -v "tag genre"
This will fail in cases where the string you're searching for is on two lines in a row. You'll have to define what behaviour you want in that case if we're going to program something sensible for it.
Another possibility would be to use a tool like awk
, which allows for greater compexity in the line selection:
cmus-remote -Q | awk '/tag genre/ { getline; print }'
This searches for the string, then gets the next line, then prints it.
Another possibility would be to do this in bash alone:
while read line; do
[[ $line =~ tag\ genre ]] && read line && echo "$line"
done < <(cmus-remote -Q)
This implements the same functionality as the awk script, only using no external tools at all. It's likely slower than the awk script.
grep lines matching a pattern, and the lines before and after the matching until different pattern
With gawk
, which supports multi char RS
:
gawk 'BEGIN{RS=ORS="End_pattern"}/ef/' file
Output:
Start_pattern
abc
d
ef
ghij
klm
no End_pattern
Start_pattern
abc
def
hij End_pattern
Explanation:
# Split records based on the End_pattern
BEGIN{RS=ORS="End_pattern"}
# Print records that contain the search term
/ef/
Btw, for cosmetic reasons you might want to append a newline at the end out the output:
gawk 'BEGIN{RS=ORS="End_pattern"}/ef/;END{printf "\n"}' file
PS: While the above solution works with gawk
only, it is also possible to achieve that with a simple awk
script which is compatible to POSIX, meaning it works with any awk
:
awk '{b=b$0"\n"}/End_pattern/{if(b~/ef/){printf "%s",b};b=""}' file
Explanation:
# Append the current line plus a newline to b(uffer)
{b=b$0"\n"}
# Once End_pattern is found ...
/End_pattern/{
# Check if the buffer contains the search term
if(b~/ef/){
# Print the buffer when the term was found
printf "%s",b
}
# Clear the buffer
b=""
}
awk '{b=b$0"\n"}/End_pattern/{if(b~/ef/){printf "%s",b};b=""}' file
How do you grep a file and get the next 5 lines
You want:
grep -A 5 '19:55' file
From man grep
:
Context Line Control
-A NUM, --after-context=NUM
Print NUM lines of trailing context after matching lines.
Places a line containing a gup separator (described under --group-separator)
between contiguous groups of matches. With the -o or --only-matching
option, this has no effect and a warning is given.
-B NUM, --before-context=NUM
Print NUM lines of leading context before matching lines.
Places a line containing a group separator (described under --group-separator)
between contiguous groups of matches. With the -o or --only-matching
option, this has no effect and a warning is given.
-C NUM, -NUM, --context=NUM
Print NUM lines of output context. Places a line containing a group separator
(described under --group-separator) between contiguous groups of matches.
With the -o or --only-matching option, this has no effect and a warning
is given.
--group-separator=SEP
Use SEP as a group separator. By default SEP is double hyphen (--).
--no-group-separator
Use empty string as a group separator.
Related Topics
History Command Works in a Terminal, But Doesn't When Written as a Bash Script
Join on First Column of Two Files
How to Use Global Arrays in Bash
How to Connect a Shell to a Pseudo Tty
Unable to Pass Wget a Variable with Quotes Inside the Variable
Starting a Shell in the Docker Alpine Container
How to Find Files Recursively by File Type and Copy Them to a Directory
Differencebetween .Got and .Got.Plt Section
Opening a .Tar.Gz File with a Single Command
Command to Get Time in Milliseconds
Why Does '/Proc/Meminfo' Show 32Gb When Aws Instance Has Only 16Gb
Bash Script to Find and Display Oldest File
Printing Variable to Command Line Using Assembly in Linux
Omitting the First Line from Any Linux Command Output