我需要根据模式从文本文件中删除行,但需要保留与模式匹配的前 n 行。
输入
% 1
% 2
% 3
% 4
% 5
text1
text2
text3
输出
%1
%2
text1
text2
text3
我使用了sed /^%/d
file 但它删除了所有以 % 开头的行,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
您还可以使用sed
orgrep
来代替运算符进行模式匹配=~
。
答案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 之间的数字仍将打印。因此,我们嵌套第二个地址来匹配该范围并跳过该行。1
2
/% [A-Za-z3-9]*/
但 awk 仍然会更好。