Grep 用循环重复模式

Grep 用循环重复模式

我有两个文件:

文件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

答案1

ABA在变量中使用eg ,grep -v "$line{1,}"会给grep提供模式ABA{1,},这意味着它会查找一个A,一个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 ")*", "");.

答案2

使用的解决方案将从中的相应行中awk删除每一行中的重复模式:file1file2

awk 'NR==FNR { pattern[NR]="^(" $0 ")*"; next } { sub(pattern[FNR], ""); print }' file1 file2

解释:

  • NR==FNR仅匹配第一个文件的条件。
  • pattern[NR]="^(" $0 ")*";从字符串构造一个模式,并使用当前行号作为索引将其添加到数组中。ABA-> =行开头^\(ABA\)*任意数量的重复字符串。ABA
  • next跳过所有进一步的处理。这会导致以下操作仅应用于第二个(及后续)文件。
  • sub(pattern[FNR], "")用空字符串替换当前行号的模式
  • print打印(修改后的)行

一个可能的解决方案使用awk它将删除file1每行中的每个模式file2

awk 'NR==FNR { pattern[count++]="^(" $0 ")*"; next } { for(i = 0; i < count; i++) sub(pattern[i], ""); print }' file1 file2

解释:

  • NR==FNR仅匹配第一个文件的条件。
  • pattern[count++]="^(" $0 ")*";从字符串构造一个模式并将其附加到数组中。ABA-> =行开头^(ABA)*任意数量的重复字符串。将是处理后的行数ABAcountfile1
  • next跳过所有进一步的处理。这会导致以下操作仅应用于第二个(及后续)文件。
  • for(i = 0; i < count; i++)循环所有模式
  • sub(pattern[i], "")用空字符串替换模式
  • print打印(修改后的)行

答案3

while read按照-bash-loop的方法,sed可以实现如下所示的技巧:

#!/bin/bash
i=0
while read pat ; do
    ((i++))
    sed -n "${i}s/^\($pat\)\{1,\}//g;${i}p" file2
done < file1

我对你对“重复模式”的解释有点困惑,我认为它应该至少出现两次,例如\{2,\}会觉得更适合我。

答案4

就这样吧,伙计:

challenge.sh

#!/bin/bash
readarray -t searchStrs < file1.txt
linesInFile=$((${#searchStrs[@]} - 1))
line=0
while [ ${line} -le ${linesInFile} ]
do
        srchStr=$(echo ${searchStrs[$line]})
        result=$(grep -E "^${srchStr}" file2.txt | sed "s@${srchStr}@@g")
        line=$((${line} + 1))
        echo ${result}
done
./challenge.sh
TRCFUJIKHRTHVFHJJHVHJJKKHGCC
FHJKGHKKBVDTHJNJ
DEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
GTHFOOLLLHHHUUJCIICXXTKCIABAGGC
cat file2.txt
ABAABAABAABAABAABAABAABAABATRCFUJIKHRTHVFHJJHVHJJKKHGCC
FFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFFRFHJKGHKKBVDTHJNJ
HHIHHIHHIHHIHHIDEDRJFKOLGCUOUUKJGLNJKKKKJKJKJGGHHBCFDII
HABHABHABHABHABHABHABHABGTHFOOLLLHHHUUJCIICXXTKCIABAGGC

相关内容