用sed

时间:2016-04-11 21:02:13

标签: sed

我想使用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行,理想情况下应该只打印整个输入

3 个答案:

答案 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 }'

有两个块用于保存内容,模式空间保留空间。第一个用于解析当前行,第二个用作备份。方法是保存保留空间处理的最后十行。

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的建议,因为在几周后更简单,更容易调试或修改。

<强>更新

您可以在前十行之后附加到保留空间并检查其中是否有超过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行。