这是一个 sed 命令,效果很好,只是在其他每一行(为了您的方便而简化):
<?php
$headers = 'From: my@email.com' . "\r\n";
$headers .= 'Content-Type: text/plain; charset=UTF-8' . "\r\n";
if($_POST["message"]) {
mail( "my@email.com", "Note To Self", $_POST["message"], $headers );
header( "Location: sent.html" );
}
?>
如果我的 testfile.txt 是
cat testfile.txt | sed -E "/PATTERN/,/^>/{//!d;}"
预期输出:
>PATTERN
1
2
3
>PATTERN
a
b
c
>PATTERN
1
2
3
>PATTERN
a
b
c
>asdf
1
2
3
>asdf
a
b
c
实际输出:
>PATTERN
>PATTERN
>PATTERN
>PATTERN
>asdf
1
2
3
>asdf
a
b
c
-一个助手-
(实际目标是找到一组模式中的一个,然后删除它后面的内容,直到下一次出现“>”符号{也删除我可以通过管道传递到 {{ 1}}})
我通过遵循我发现的 here 或多或少得到了指导。我已经为我完成了这项工作。这是一个确切的示例(不是您有要查看的文件)
>PATTERN
>PATTERN
a
b
c
>PATTERN
>PATTERN
a
b
c
>asdf
1
2
3
>asdf
a
b
c
答案 0 :(得分:2)
/PATTERN/,/^>/
将从包含 PATTERN
的行匹配到以 >
开头的行(可以是包含 PATTERN
的行)。您应该改为匹配一个空行,如下所示:
$ sed '/PATTERN/,/^$/{/PATTERN/!d}' ip.txt
>PATTERN
>PATTERN
>PATTERN
>PATTERN
>asdf
1
2
3
>asdf
a
b
c
你的旁白对我来说不是很清楚,但如果你也想删除带有 PATTERN
的行,你可以将其简化为:
$ sed '/PATTERN/,/^$/d' ip.txt
>asdf
1
2
3
>asdf
a
b
c
您也可以使用:
awk -v RS= -v ORS='\n\n' '!/PATTERN/'
但它在输出的末尾会有一个额外的空行。优点是您可以这样做,而不是您的 for
循环:
awk 'BEGIN{FS="\n"; ORS="\n\n"}
NR==FNR{a[">" $0]; next}
!($1 in a)' bad_results.txt RS= 16S.fasta
以上代码将 bad_results.txt
的每一行存储在一个关联数组中,以 >
字符为前缀。然后,仅当 16S.fasta
中不存在以 >
开头的整行时,才会打印 bad_results.txt
的内容。
如果您想要部分匹配:
awk 'BEGIN{FS="\n"; ORS="\n\n"}
NR==FNR{a[$0]; next}
{for (k in a) if(index($1, k)) next; print}' bad_results.txt RS= 16S.fasta
答案 1 :(得分:1)
这可能对你有用(GNU sed):
sed -E '/PATTERN/{p;:a;$!{N;/\n>/!s/\n//;ta};D}' file
如前所述,范围运算符匹配从 PATTERN
到以 >
开头的行。后一行也可能包含 PATTERN
但不匹配,因此是交替模式。
上述解决方案不使用范围运算符,而是收集从第一个包含 PATTERN
的行到以 >
开头的行之前的行。
如果一行包含 PATTERN
,则将其打印出来,然后收集后续行,直到文件结束或一行开始 >
。
在这个集合中,换行符被删除 - 基本上使模式空间中的第一行成为一个或多个行的串联。
在匹配(或文件结尾)时,删除这一长行,并处理仍在模式空间中的任何行,就好像它已作为正常 sed 循环的一部分读入一样。
注意d
和 D
命令之间的区别在于 d
命令删除模式空间并立即开始下一个 sed 循环,包括读取下一行输入。而 D
命令删除所有内容,直到并包括模式空间中的第一个换行符,然后开始下一个 sed 循环。但是,如果模式空间不为空,则放弃从输入读取下一行,然后恢复 sed 循环。
另一种选择:
sed '/^>/{h;/^>PATTERN/p};G;/\n>PATTERN/!P;d' file
答案 2 :(得分:1)
在您的范围模式匹配中,第二个元素“消耗”了该行,因此范围的开头不再将该块视为匹配项。这就是为什么你显然有“跳过”的原因。这可以通过使用不消耗字符进行匹配的前瞻来解决。不幸的是,sed
缺乏前瞻。
Perl
确实是比 sed
更好的选择。
这是一个 Perl,它读取文件并将正则表达式 /(?:^>PATTERN)|(?:^>[\s\S]*?)(?=\v?^>|\z)/
(Demo) 应用到它:
$ perl -0777 -lnE 'while(/(?:^>PATTERN)|(?:^>[\s\S]*?)(?=\v?^>|\z)/gm) { say $& }' file
>PATTERN
>PATTERN
>PATTERN
>PATTERN
>asdf
1
2
3
>asdf
a
b
c
旁白:请阅读Looping through the content of a file in Bash。你这样做的方式不是想法。具体来说,read here 在 Bash 循环中使用 cat
的副作用。
答案 3 :(得分:0)
回答关于为什么的问题,它似乎跳过了所有其他事件 (正如 Sundeep 回答的评论中所充实的那样。请参阅他的回答以解决此问题)
明显的跳跃只是一种错觉。 sed 是贪婪的;它找到了 PATTERN
的第一次出现,直到 并包括 以 >
开头的下一行。然后它会删除(按照指示)之间的所有内容。 sed 然后从它停止的地方继续,因此不会“看到”最后一行作为新的出现
要清楚:
>PATTERN <--- sed see's the first occurrence here------------------|
a |(this whole
a |chunk is
a |considered
|by sed)
>PATTERN <--- then matches up to here (the next occurence of ">")--|
b <--- then continues from here "missing" the match of PATTERN above
b
b
>PATTERN
c
c
c