Bash

帶循環的 Grep 重複模式

  • July 21, 2022

我有兩個文件:

文件1:

ABA
FFR
HHI
HAB

文件2:

ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC

file1 中的每一行都是在 file2 中相應行的開頭重複的模式。我想從 file2 中獲取不是 file1 中重複模式的每一行的部分。

所需的輸出:

TRCFUJIKHRTHVFHJJHVHJJKKHGCC
FHJKGHKKBVDTHJNJ
DEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
GTHFOOLLLHHHUUJCIICXXTKCIABAGGC

我嘗試使用這個循環:

while read -r line
do

grep -v "$line{1,}"   file2.txt 

done < file1.txt

但我去這個輸出:

ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC

使用 egABA在變數中,grep -v "$line{1,}"會給 grep 模式ABA{1,},這意味著它會尋找一個 single A,一個 single B,然後至少一個A。不過,最後一次重複並不重要,因為在那之後就什麼都沒有了,所以即使是一個重複也ABA可以匹配。

好吧,除了預設情況下,grep 使用基本正則表達式 (BRE),其中計數的重複必須用反斜杠書寫,如. 在擴展正則表達式 (ERE) 中,是否會有一個或多個重複(也會如此);但在 BRE 中,它只是四個文字字元(也是正常字元)。\{*n*,*m*\}``{1,}``+``+

但是 grep 列印匹配或不匹配的完整行;-v它不會刪除部分行。(除了grep -o它只列印匹配部分的地方,但我認為這不適用於-v.)另外,使用該循環,grep將查看每個模式的所有行,這就是為什麼你會得到file2重複多次的內容.


我們需要一個循環,在每次迭代時從每個輸入中讀取一行。它可以在shell中完成,但它會很慢。像 AWK 這樣的東西會更好,例如:

$ awk '{getline pat < "file1"; sub("^(" pat ")*", ""); print}' file2
TRCFUJIKHRTHVFHJJHVHJJKKHGCC
FHJKGHKKBVDTHJNJ
DEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
GTHFOOLLLHHHUUJCIICXXTKCIABAGGC

AWK 程序隱式循環遍歷(和命令行上給出的其他文件)的行,在這裡,我們從每次迭代中file2顯式讀取一行。file1然後"^(" pat ")*"構造一個類似 的模式^(ABA)*,它與目前行匹配,並用空字元串替換。

這不會從行中刪除任何模式實例,例如ABAABAFOOABABAR會變成FOOABABAR. 如果您也想刪除它們,請將其更改為gsub("(" pat ")*", "");.

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