I have a file with multiple lines:
line1
line2
line3
line_before
line4
line5
line6
and 3 patterns:
line2
line4
line6
Expect:
line2
line_before
line4
line6
I try use grep -B 1
but it show line before any patterns.
Thank you for any help!
CodePudding user response:
With awk...
In my exemple, your file with multiple lines is named "file.txt
" and the file with 3 patterns is filem.txt
.
The awk filter.awk
program:
#! /bin/awk -f
NR == FNR && NR != 2 {
# First file: Save 1st en 3rd tokens
m[$0]=1
next
}
NR == FNR && NR == 2 {
# First file: Save 2nd token
b[$0]=1
next
}
NR != FNR {
# Second file
# Search line in tokens
for (e in m) {
if ($0 == e) {
# Print current line
print
old = $0
next
}
}
for (e in b) {
if ($0 == e) {
# Print previous line
if (FNR > 1) print prev
# Print current line
print
old = $0
next
}
}
}
{
# Save current line
prev = $0
}
Execute like this (files order is very important):
awk -f filter.awk filem.txt file.txt
Output:
line2
line_before
line4
line6
CodePudding user response:
I am assuming you want -B1
for only -e line4
. (I would phrase that as: "How can I grep for multiple patterns, including the line before only one?")
Suggestions with grep -zPo
:
grep -zPo '\v\K(line[26]|\V*\vline4)(?=\v)' file
or (same regex, different syntax):
grep -zPo '(?<=\v)(line[26]|\V*\vline4)(?=\v)' file
Both output this:
line2
line_before
line4
line6
Explanation:
-z
: consume entire file-P
support perl regexes-o
: output only matching strings (one line at a time)\v
: vertical whitespace character\v\K
or(?<=\v)
: Require vertical whitespace before match, but do not include it in match(?=\v)
: require vertical whitespace after match, but do not include it in the match\V*\vline4
: for theline4
pattern, include the preceeding line (all not-vertical-whitespace-chars, a linebreak, and then the matching line -- to mimicgrep -B1 line4