根据模式删除行,但保留前 n 行匹配

根据模式删除行,但保留前 n 行匹配

我需要根据模式从文本文件中删除行,但需要保留与模式匹配的前 n 行。

输入

% 1 
% 2
% 3
% 4
% 5
text1
text2
text3

输出

%1
%2
text1
text2
text3

我使用了sed /^%/dfile 但它删除了所有以 % 开头的行,sed 3,/^%/d也不起作用。我需要保留模式的前 n 行并删除其余的

答案1

如果您想删除以 % put 开头的所有行,保留前两行输入,您可以这样做:

sed -e 1,2b -e '/^%/d'

尽管使用以下命令会更清晰awk

awk 'NR <= 2 || !/^%/'

或者,如果您追求性能:

{ head -n 2; grep -v '^%'; } < input-file

如果您想保留与模式匹配的前两行,而它们可能不是输入的第一行,那么awk肯定是一个更好的选择:

awk '!/^%/ || ++n <= 2'

使用sed,您可以使用以下技巧:

sed -e '/^%/!b' -e 'x;/xx/{h;d;}' -e 's/^/x/;x'

也就是说,使用保留空间来计算迄今为止匹配的模式的出现次数。效率不高,也不清晰。

答案2

恐怕sed单独这样做有点太简单了(并不是说这是不可能的,而是相当复杂 - 参见例如sed 推箱子可以做什么)。

怎么样awk

#!/bin/awk -f
BEGIN { c = 0; }
{
    if (/^%/) {
        if (c++ < 3) {
            print;
        }
    } else {
        print;
    }
}

如果您可以依赖使用最新的 BASH(支持正则表达式),上面的 awk 可以翻译为:

#!/bin/bash -
c=0
while IFS= read -r line; do
    if [[ $line =~ ^% ]]; then
        if ((c++ < 3)); then
            printf '%s\n' "$line"
        fi
    else
        printf '%s\n' "$line"
    fi
done

您还可以使用sedorgrep来代替运算符进行模式匹配=~

答案3

珀尔一句台词解决方案:

# in-place editing
perl -i -pe '$.>2 && s/^%.*//s' filename.txt

# print to the standard output
perl -ne '$.>2 && /^%/ || print' filename.txt

答案4

sed '/^%/{
3,$d}' '% 1 
% 2
% 3
% 4
% 5
text1
text2
text3'

删除多余线条的一种方法。

编辑:我的答案在与 s 相同的条件下工作Stephane Chazelas,如果 % 行不首先出现,它将不起作用。


书呆子狙击。

sed -n '/^% [^12]*$/!{
/^% [12][[:digit:]]\{1,\}/n
p}' file.txt

无论% number字符串在流中的何处找到,都将起作用。任何以或%之外的任意数量的字符开头和结尾的行,我们将其取反。该地址除了留下盲点外,与任何内容都匹配。 10-29 之间的数字仍将打印。因此,我们嵌套第二个地址来匹配该范围并跳过该行。12/% [A-Za-z3-9]*/

但 awk 仍然会更好。

相关内容