使用sed仅删除文件的中间部分

使用sed仅删除文件的中间部分,sed,awk,Sed,Awk,我想使用sed作为管道的一部分,只保留输入的10行第一行和10行最后一行。它不会处理物理文件,而只是从STDIN读取数据并输出到STDOUT。流中的数据量大于机器RAM(或其磁盘空间),因此需要相对高效。它还必须在流模式下工作,而不创建临时文件(无可写文件系统) 如果可以显示一行而不是删除的所有中间行,则会获得额外奖励: 例如,如果我的输入行包含从1到100000的数字,我需要它来输出(带有literal文本的行很好,但是是可选的): 哪个输出 1 2

我想使用sed作为管道的一部分,只保留输入的10行第一行和10行最后一行。它不会处理物理文件,而只是从STDIN读取数据并输出到STDOUT。流中的数据量大于机器RAM(或其磁盘空间),因此需要相对高效。它还必须在流模式下工作,而不创建临时文件(无可写文件系统)

如果可以显示一行而不是删除的所有中间行,则会获得额外奖励:

例如,如果我的输入行包含从1到100000的数字,我需要它来输出(带有literal
文本的行很好,但是是可选的):

哪个输出

     1   
     2   
     3   
     4   
     5   
     6   
     7   
     8   
     9   
    10   
100000   
但我也需要它在数据末尾输出更多的上下文(10行而不是1行)

更新:输入流的长度未知且会发生变化,
100000
以上只是一个示例

更新:如问题和标签中所述,我需要的是sed,而不是awk、perl或其他更容易实现的编程语言(这一要求,加上没有tmp文件,是因为它是嵌入式系统,可用的命令和资源有限)


更新:如果输入少于10+10行,理想情况下,它应该只打印整个输入

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
$cat tst.awk
开始{beg=(beg?beg:3);结束=(end?end:3)}

NR您可以尝试以下命令:

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
现在,更具挑战性的是要知道在20行输入的边缘情况下在何处添加
字符串,但我将把它作为一个练习留给您。

这可能适用于您(GNU-sed):

sed'1,10b;:a、 美元!{N;s/\N/&/10;Ta;D};i\'文件

正常打印前10行。收集接下来的11行,如果不是文件的结尾,则删除其中的第一行,并始终保持最后10行。在文件末尾插入一行,其中包含
,然后打印剩余的10行。

谢谢!如果我有选择的话,我会用可读的perl(它可以存在,真的:),但我还是坚持使用sed。这看起来几乎完美,但当输入只有15行时是异常的。我知道我在这里为sed扩展它,但是它可以只打印整个输入而不是复制行吗?
sed -n 'H; 1,10 { p; b }; g; s/\n[^\n]*//; h; $ { s/\n/<cut>\n/; p }'
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
sed -n '1,10 { p; b }; H; g; /\(\n[^\n]\+\)\{11\}/ s/\n[^\n]*//; h; $ { s/^\n//; p }'
sed '1,10b;:a;$!{N;s/\n/&/10;Ta;D};i\<cut>' file