Shell-Script

如何grep除匹配項和上一行之外的所有內容

  • October 7, 2022

我有一個文本文件,並且我有一個不希望 grep 匹配的模式。問題是,我也希望之前的行不匹配。

我的文件:

line 1
line 2
pattern
line 4

我試過cat file | grep -v pattern了,它輸出:

line 1
line 2
line 4

然後我嘗試cat file | grep -B 1 pattern了,它輸出:

line 2
pattern

但是,當我同時使用它們時cat file | grep -v -B 1 pattern,我得到:

line 2

我怎樣才能使輸出為:

line 1
line 4

我傾向於只在grep從文件中提取單行時使用,所以當我需要在文本中執行更複雜的編輯時,我會使用其他工具。

這裡的所有解決方案都假定該模式可能在文本中出現多次,並將刪除出現該模式的行和緊接在它們之前的行。如果模式在連續行上匹配,前兩個解決方案將出現問題。


您可以使用sed匹配模式/pattern/並讓其觸發命令Nand d,它將下一行附加到緩衝區,然後丟棄兩者:

sed '/pattern/ { N; d; }' file

由於您想丟棄模式匹配之前的行,因此我們將數據向後饋入sed,從最後一行開始並移至文件的開頭。然後我們在sed完成後再次反轉數據。

tac file | sed '/pattern/ { N; d; }' | tac

tac實用程序是 GNU coreutils 的一部分。

如果模式匹配兩個連續的行,這將無法刪除第一行之前的行(因為第一行將被刪除)。


使用ed編輯器:

printf '%s\n' 'g/pattern/ -1,. d' ,p Q | ed -s file

這會將命令應用於g/pattern/ -1,. d文件的內容。此命令搜尋與 匹配的每一行,pattern然後刪除該行及其之前的行。

最終,pQ編輯命令列印整個文件並退出編輯器而不保存。

如果模式匹配兩個連續的行,這將在刪除第一行之前的行之後刪除成為第二行之前的行。

(最後一句寫的時候是對的,但顯然是只寫句。)


我們還可以使用grep它的非標準但通常實現-B的選項來為我們提供需要刪除的行號。這些數字可以轉換為sed我們在原始數據上執行的腳本:

grep -n -B1 'pattern' file | sed 's/[:-].*/d/' | sed -f /dev/stdin file

給定問題中的文本,該grep命令將輸出

2-line 2
3:pattern

…並且第一個sed命令將其轉換為sed編輯命令2d,然後是3d(“刪除第 2 行和第 3 行”)。管道中的最後一個sed命令採用此編輯腳本並將其應用於原始文本。

這個變體對於匹配模式的連續行沒有問題,因為它使用一種 2-pass 方法,首先找到所有應該刪除的行,然後刪除它們(而不是在第一次閱讀文本時刪除行)。

引用自:https://unix.stackexchange.com/questions/720025