删除所有行,在/ pattern /之后开始两行

时间:2017-02-02 14:30:02

标签: bash sed

想象一下,我有一个文件如下:

drink
eat
XXX
pizza
blunzn
sushi

我想从模式XXX之后的第三行开始删除文件中的所有行,因此结果应如下所示:

drink
eat
XXX
pizza
blunzn

删除XXX之后的所有行很简单:

sed -e '/XXX/q' -i data.txt

但是,我发现在删除模式后很难跳过固定数量的行。

到目前为止我想出的最好的是:

 sed -e '/XXX/ { N; N; q }' -i data.txt

是否有更优雅的东西,而不是添加n * N(想象一下,我想跳过50行)??

5 个答案:

答案 0 :(得分:3)

我会使用awk,变量n表示匹配/XXX/之后要打印的行数:

awk -v n=2 'seen && !n-- { exit } /XXX/ { seen = 1 } 1' file
在匹配正则表达式之前,

seen未初始化( false ),因此不会评估!n--。当正则表达式匹配时,seen设置为 true

seen 为真时,&&的两边都会被评估,因此n每行减少一次。当n到达0时,!n变为 true ,因此脚本会退出。

最后的1始终是 true ,因此在脚本退出之前,每行都会打印出来。

答案 1 :(得分:1)

对于sed,我只能想出一些有点模糊的东西,需要GNU扩展来解决:

sed '1,/XXX/{/XXX/!b};/XXX/,+2b;d' infile

或评论:

1,/XXX/ {      # From the first line until the pattern
    /XXX/! b   # Print (by skipping all commands), except when on pattern line
}
/XXX/,+2 b     # For pattern line and the following two, print by skipping commands
d              # Don't print line

GNU扩展是/pattern/,+N寻址方案。

需要/XXX/!位以避免两次打印图案线。

参数化为模式后的行数:

n=2
sed "1,/XXX/{/XXX/"\!"b};/XXX/,+${n}b;d" infile

要求!进行奇数转义,以防止解释为历史扩展命令。

如果输入文件真的很长并且处理(而不是打印)图案后面的线加上所需的线需要太长时间,我们可以翻转它而不是默认打印,然后退出:

sed -n '1,/XXX/{/XXX/!{p;b}};/XXX/,+2{p;b};q' infile

答案 2 :(得分:1)

n=3
csplit -s data.txt "/XXX/+${n}"
rm xx01

您的结果位于xx00。这会将模式XXX,行偏移${n}的文件分成两个文件xx00xx01,前者包含您想要的内容。您可以更改输出文件的前缀和/或格式。如果您有多个XXX,它会生成更多文件。

答案 3 :(得分:1)

这可能适合你(GNU sed):

sed '/pattern/{:a;N;s/\n/&/2;Ta;q}' file

在遇到所需的模式时,循环所需的行然后退出。

对于遵循所需模式的50行,请使用:

sed '/pattern/{:a;N;s/\n/&/50;Ta;q}' file

答案 4 :(得分:0)

Bash相当于Tom Fenech's elegant awk

n=2
while IFS= read -r line || [[ -n $line ]]; do 
    if [ $seen ] && ! ((n--)); then
        break
    fi
    if [[ "$line" =~ ^XXX ]]; then 
        seen=1
    fi  
    echo "$line"
done <file   >filtered