想象一下,我有一个文件如下:
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行)??
答案 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}
的文件分成两个文件xx00
和xx01
,前者包含您想要的内容。您可以更改输出文件的前缀和/或格式。如果您有多个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