我有两个文件:
文件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
删除每一行中的重复模式:file1
file2
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)*
任意数量的重复字符串。将是处理后的行数ABA
count
file1
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