以Y行间隔提取长度为X的行

时间:2017-10-26 13:30:36

标签: linux awk sed

我的测试数据

aa1
bb1
cc1
aa2
bb2
cc2
aa3
bb3
cc3
aa4
bb4
cc4
aa5
bb5
cc5
aa6
bb6
cc6
aa7
bb7
cc7
aa8
bb8
cc8

假设我希望将4-6行(aa2-cc2)提取到文件中,然后跳过6行并提取行13-15(aa5-cc5),然后跳过6行。该过程将重复直到文件结束。我写了一个bash脚本,适用于小文件。

#!/bin/bash
for i in {2..8..3}; do

sed -n "$((3*i-2))","$((3*i))"p testdata > "$i".part

done

现在我正在处理一个30 GB的巨型文件,我的脚本对于硬盘是不好的,因为它将读取相同的文件数千次。我希望通过只读取(并提取我的部分)文件一次来避免硬盘损坏。是否有可以解决我的问题的单线程?

我不是一个真正的程序员,所以请在我的问题中混淆任何术语混淆。谢谢你的帮助!

5 个答案:

答案 0 :(得分:3)

只需单次传递文件即可。加上一点算术。

display: flex;
justify-content: center;
align-items:center

答案 1 :(得分:3)

在GNU sed中,可以使用first~step line addressing

sed -n '4~9p; 5~9p; 6~9p' file

答案 2 :(得分:3)

你可以在sed中进行循环,例如与GNU sed:

# Skip first 3 lines, extract 3 lines and skip 6
sed -n '4~9 { N; N; p }'

使用示例:

seq 40 | sed -n '4~9 { N; N; p }'

输出:

4
5
6
13
14
15
22
23
24
31
32
33

请注意,此解决方案仅打印整个文本块。如果最后一个块中没有足够的行,则不会打印它,即上例中的40,41,42

解释

  • 4~9告诉sed,从第4行开始,每9行只执行一次代码块
  • { N; N; p }因此,对于每9行,我们再获取2行(N; N),然后将它们全部打印p

答案 3 :(得分:1)

IIUC,您想要提取行并写入某个文件,如果是这样,如果您可以再创建一个文件来提取带有范围的记录列表,那么您可以尝试下面的一个,

假设您有一个名为extract的文件,其中包含您感兴趣的范围

$ cat extract 
4-6
13-15

这是您的输入文件

$ cat file
aa1
bb1
cc1
aa2
bb2
cc2
aa3
bb3
cc3
aa4
bb4
cc4
aa5
bb5
cc5
aa6
bb6
cc6
aa7
bb7
cc7
aa8
bb8
cc8

如果执行如下:

$ awk -F'[- ]' 'FNR==NR{rules[FNR,"min"]=$1;rules[FNR,"max"]=$2;m=FNR;next}function is_in_list(i){for(i=1; i <=m; i++)if(FNR>=rules[i,"min"] && FNR<=rules[i,"max"])return rules[i,"min"]"-"rules[i,"max"]".txt"}{file=is_in_list()}file{ if(file in arr){ print >>file }else{ print >file; arr[file] } close(file) }' extract file

你得到:

$ ls *.txt
13-15.txt  4-6.txt

每个文件的内容如下:

$ cat 4-6.txt 
aa2
bb2
cc2

$ cat 13-15.txt 
aa5
bb5
cc5

如果您只想列出行

$ awk -F'[- ]' 'FNR==NR{rules[FNR,"min"]=$1;rules[FNR,"max"]=$2;m=FNR;next}function is_in_list(i){for(i=1; i <=m; i++)if(FNR>=rules[i,"min"] && FNR<=rules[i,"max"])return rules[i,"min"]"-"rules[i,"max"]".txt"}is_in_list()' extract file
aa2
bb2
cc2
aa5
bb5
cc5

写入单个文件的更好的可读性:

awk -F'[- ]' '
               FNR==NR{
                   rules[FNR,"min"]=$1;
                   rules[FNR,"max"]=$2;
                   m=FNR;
                   next
               }
               function is_in_list(i)
               {
                   for(i=1; i <=m; i++)
                      if(FNR>=rules[i,"min"] && FNR<=rules[i,"max"])
                          return rules[i,"min"]"-"rules[i,"max"]".txt"
               }
               {
                  file=is_in_list()
               }
           file{ 
                  if(file in arr){ 
                      print >>file 
                  }
                  else{ 
                      print >file; 
                      arr[file] 
                  } 
                  close(file) 
            }
          ' extract file

对于给定范围

,列表行更易于阅读
awk -F'[- ]' '
               FNR==NR{
                   rules[FNR,"min"]=$1;
                   rules[FNR,"max"]=$2;
                   m=FNR;
                   next
               }
               function is_in_list(i)
               {
                   for(i=1; i <=m; i++)
                      if(FNR>=rules[i,"min"] && FNR<=rules[i,"max"])
                          return rules[i,"min"]"-"rules[i,"max"]".txt"
               }
               is_in_list()
          ' extract file

答案 4 :(得分:0)

关注awk也可以帮助你。

awk '
function jump(var){
  while(var>0){
    getline;
    var--
}}
FNR==4{
  val++
}
val>=1&&val<=3{
  print $0;
  val++
}
val==4{
  jump(val+2);
  val=1
}
'   Input_file

输出如下。

aa2
bb2
cc2
aa5
bb5
cc5
aa8
bb8
cc8