我有一个包含如下行的文件:
ABCDABCBCBBBCBCDDBBBBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDCCCBCCBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDACDCDCCCCBBBBBBBBBBBBBBBBBBBBBBBBXYZ
而且我要
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ
因此,目标是删除从ABCD
4 个连续 s 的第一次出现开始的所有内容(包括第一次出现的内容)B
。保证所有行都以 开头,并且在结束之前的 s的“相关”链之前,该行上ABCD
不能有“杂散” 。BBBB
B
XYZ
我尝试过sed
与此接近的变体:
sed 's/ABCD.*BBBB//g' filename
我认为这给了我XYZ
,因为它直到最后一个模式才停止BBBB
,但我希望它在第一个模式之后停止。
任何帮助将不胜感激!!
答案1
sed
正如您所怀疑的,您的方法失败的原因是它sed
基于正则表达式,并且这些是“贪婪的”,即它们尝试匹配它们可以描述的最长的可能字符串。
所以,这可能是 的任务awk
。考虑这个程序:
awk '{n=index($0,"BBBB"); print substr($0,n+4)}' input.txt
BBBB
这将定位当前行中第一次出现的子字符串(用 表示$0
)并将位置存储在 中n
。然后它将打印从该位置开始的行部分加上 4(以删除最初的 4B
秒)直到行尾。
请注意,此处没有提及起始模式,ABCD
因为您的示例输入表明全部行以 开头ABCD
,在这种情况下,删除从行开头到(包括第一个 4- -)模式的所有内容就足够了B
。如果假设不正确,特别是如果BBBB
可以发生在 之前ABCD
,它将无法按预期工作。
答案2
做你该做的事问对于 ( remove everything starting with the ABCD up to, and including, the first occurence of 4 consecutive Bs.
) 与任何 awk 都将是:
$ awk -v beg='ABCD' -v end='BBBB' '
{ gsub(end,"\n") }
match($0,beg"[^\n]+\n") { $0=substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH) }
{ gsub(/\n/,end) }
1' file
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ
无论 ABCD 是行中的第一个还是 BBBB 可以出现在它之前,这都有效:
$ echo 'xyz BBBB foo ABCD bar BBBB etc BBBB anon' |
awk -v beg='ABCD' -v end='BBBB' '{gsub(end,"\n")} match($0,beg"[^\n]+\n"){$0=substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)} {gsub(/\n/,end)} 1'
xyz BBBB foo etc BBBB anon
答案3
如果序列仅出现一次BBBB*
,则可以指示sed
仅删除BBBB
前面的第一个序列其他特点。
sed 's/^ABCD.*[^B]BBBB//'
如果BBBB
序列每行只开始一次,那么应该可以完成工作。
请注意,它不适用于以下字符串:
ABCDEBBBBFBBBBXYZ
因为这是两次出现的情况BBBB
,前面有非 B,贪心算法也会捕获第二次。
答案4
问题在于sed
的正则表达式是“贪婪的”(即它们尝试尽可能多地匹配)。 sed
没有用于匹配的非贪婪量词,但perl
有 - 只需附加?
在您要匹配的内容之后。例如
$ sed 's/ABCD.*BBBB//g' input.txt
XYZ
XYZ
XYZ
$ perl -p -e 's/ABCD.*?BBBB//g' input.txt
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ
顺便说一句,像您这样的大多数简单脚本都可以使用代替(或在适当的情况下使用语句,而不是命令)sed
来运行- 但使用perl正则表达式而不是perl -p -e
sed
perl -n -e
print
sed -n
p
布雷(sed 的默认值)或 ERE ( sed -E
)。请注意,与 不同sed
,-e
指示下一个参数是脚本的 对于 来说不是可选的perl
。
从man perlre
:
默认情况下,量化子模式是“贪婪的”,也就是说,它将匹配尽可能多的次数(给定特定的起始位置),同时仍然允许模式的其余部分匹配。如果您希望它匹配尽可能少的次数,请在量词后面加上
?
。请注意,含义没有改变,只是“贪婪”:*? Match 0 or more times, not greedily +? Match 1 or more times, not greedily ?? Match 0 or 1 time, not greedily {n}? Match exactly n times, not greedily (redundant) {n,}? Match at least n times, not greedily {n,m}? Match at least n but not more than m times, not greedily