
使用grep
,我想選擇與某個模式匹配且與另一個模式不匹配的所有行。我希望能夠使用一次調用,grep
以便我可以使用--after-context
選項(或--before-context
、 或--context
)。
-v
在這裡不可行,因為它否定了我傳遞給grep
使用該-e
選項的所有模式。
例子
我想尋找匹配的行needle
,忽略匹配的行ignore me
,並帶有一行以下上下文。
這是我的輸入檔:
one needle ignore me
two
three
four needle
five
我想要的輸出是:
four needle
five
正如您所看到的,這個簡單的解決方案不起作用:
$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five
答案1
如果你有 GNU grep,你可以使用Perl正規表示式,其中有一個否定結構。
grep -A1 -P '^(?!.*ignore me).*needle'
如果你沒有 GNU grep,你可以在 awk 中模擬其前後上下文選項。
awk -v after=3 -v before=2 '
/needle/ && !/ignore me/ {
for (i in h) {
print h[i];
delete h[i];
}
until = NR + after;
}
{
if (NR <= until) print $0; else h[NR] = $0;
delete h[NR-before];
}
END {exit !until}
'
答案2
您似乎正在使用 GNUgrep。使用 GNU grep,您可以傳入--perl-regex
標誌來啟動 PCRE,然後提供否定的先行斷言,範例如下
grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five
這裡要注意的主要事情是(?:(?!STRING).)*
is to STRING
as [^CHAR]*
is toCHAR
答案3
我建議使用 awk 來代替,因為它可以更好地處理多行 IO。任何一個1)將結果透過管道傳輸到 GNU awk--\n
作為記錄分隔符,或者2)在 awk 中進行所有配對。
選項1
<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'
輸出:
four needle
five
--
請注意,此選項在整個記錄中搜尋ignore me
、設定FS=1
並匹配$1
以僅與第一行進行比較。
選項2
<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1