我想使用sed作为管道的一部分来保留其输入的10个第一行和第10行。它不会处理物理文件,只是从STDIN读取并输出到STDOUT。流中的数据量大于机器RAM(或其磁盘空间),因此需要相对高效。它也必须在流模式下工作,而不创建临时文件(没有可写文件系统)。
额外奖励,如果它可以显示一行而不是所有删除的中间部分:
例如,如果我的输入行包含1到100000之间的数字,我需要输出(带文字<cut>
文本的行会很好,但是可选):
1
2
3
4
5
6
7
8
9
10
<cut>
99991
99992
99993
99994
99995
99996
99997
99998
99999
100000
我提出的最好的方法是让它输出前10行,最后一行输出:
yes ' ' | head -n 100000 |nl | \
sed -e '$q;11,$d'`
输出
1
2
3
4
5
6
7
8
9
10
100000
但我需要它在数据末尾输出更多上下文(10行而不是1行)。
更新:输入流的长度未知且会有所不同,上面的100000
只是一个示例。
更新:如问题和标记中所述,我需要 sed ,而不是awk,perl或其他更容易实现的编程语言(该要求,连同没有tmp文件,是因为它是嵌入式系统,可用的命令和资源有限)
更新:如果输入小于10 + 10行,理想情况下应该只打印整个输入
答案 0 :(得分:3)
sed用于单行上的简单替换,即全部。对于其他任何事情,包括此任务,您应该使用awk:
$ cat tst.awk
BEGIN { beg=(beg?beg:3); end=(end?end:3) }
NR<=beg
{ rec[(NR-1)%end+1] = $0 }
END {
print "<cut>"
for (i=1;i<=end;i++) {
print rec[(NR+i-1)%end+1]
}
}
$ seq 10 | awk -f tst.awk
1
2
3
<cut>
8
9
10
$ seq 10 | awk -v beg=2 -v end=4 -f tst.awk
1
2
<cut>
7
8
9
10
我看到你添加了一个&#34;它必须是sed&#34;对你的问题的要求,但我会在这里留下这个答案,供未来的读者寻找合理的方式来完成任务。
答案 1 :(得分:3)
您可以尝试以下命令:
sed -n 'H; 1,10 { p; b }; g; s/\n[^\n]*//; h; $ { s/\n/<cut>\n/; p }'
sed有两个块用于保存内容,模式空间和保留空间。第一个用于解析当前行,第二个用作备份。方法是保存保留空间处理的最后十行。
H
将每行保存到保留空间,g
恢复保留空间,然后删除最旧的行并再次保存到保留空格,并在最后一行($
)打印,在它前面添加你的魔法字。
整个命令:
yes ' ' | head -n 100000 |nl|\
sed -n 'H; 1,10 { p; b }; g; s/\n[^\n]*//; h; $ { s/\n/<cut>\n/; p }'
收率:
1
2
3
4
5
6
7
8
9
10
<cut>
99991
99992
99993
99994
99995
99996
99997
99998
99999
100000
并且说,请遵循Ed Morton的建议,因为awk在几周后更简单,更容易调试或修改。
<强>更新强>
您可以在前十行之后附加到保留空间并检查其中是否有超过10个换行符,然后删除最旧的FIFO结构:
sed -n '1,10 { p; b }; H; g; /\(\n[^\n]\+\)\{11\}/ s/\n[^\n]*//; h; $ { s/^\n//; p }'
现在了解在20个输入行的边缘情况下添加<cut>
字符串的位置更具挑战性,但我会将其留作练习。
答案 2 :(得分:1)
这可能对您有用(GNU sed):
sed '1,10b;:a;$!{N;s/\n/&/10;Ta;D};i\<cut>' file
正常打印前10行。收集接下来的11行,如果不是文件末尾,则删除其中的第一行,并始终保持最后10行重复。在文件末尾,插入包含<cut>
的行,并打印剩余的10行。