按可变范围的行拆分文件

时间:2016-03-09 23:39:28

标签: linux awk split

我有一个大文件,其中每行中的第三个元素$3是表示时间的值。

我想拆分我的文件,这样我就会得到几个文件,每个文件都有一段时间的行。行数可以从文件更改为另一个。

示例

输入文件:

$xx_ at 0.0 "$elt_(0) coordinates 656.02 1819.19 0.00"
$xx_ at 1.0 "$elt_(0) coordinates 654.99 1818.19 1.44"
$xx_ at 1.0 "$elt_(1) coordinates 365.41 1284.31 0.00"
$xx_ at 4.0 "$elt_(0) coordinates 652.74 1816.04 3.12"
$xx_ at 4.0 "$elt_(1) coordinates 365.7 1281.79 2.54"
$xx_ at 5.0 "$elt_(0) coordinates 649.08 1812.52 5.08"
$xx_ at 5.0 "$elt_(1) coordinates 366.2 1277.44 4.37"
$xx_ at 8.0 "$elt_(0) coordinates 643.59 1807.23 7.62"
$xx_ at 8.0 "$elt_(1) coordinates 366.88 1271.47 6.01"
$xx_ at 10.0 "$elt_(0) coordinates 636.46 1800.37 9.90"
$xx_ at 10.0 "$elt_(1) coordinates 367.78 1263.63 7.90"

如果我想以5秒的间隔分割,我将有3个文件:

file1

$xx_ at 0.0 "$elt_(0) coordinates 656.02 1819.19 0.00"
$xx_ at 1.0 "$elt_(0) coordinates 654.99 1818.19 1.44"
$xx_ at 1.0 "$elt_(1) coordinates 365.41 1284.31 0.00"
$xx_ at 4.0 "$elt_(0) coordinates 652.74 1816.04 3.12"
$xx_ at 4.0 "$elt_(1) coordinates 365.7 1281.79 2.54"
$xx_ at 5.0 "$elt_(0) coordinates 649.08 1812.52 5.08"
$xx_ at 5.0 "$elt_(1) coordinates 366.2 1277.44 4.37"

file5

$xx_ at 8.0 "$elt_(0) coordinates 643.59 1807.23 7.62"
$xx_ at 8.0 "$elt_(1) coordinates 366.88 1271.47 6.01"
$xx_ at 10.0 "$elt_(0) coordinates 636.46 1800.37 9.90"
$xx_ at 10.0 "$elt_(1) coordinates 367.78 1263.63 7.90"

file10

$xx_ at 13.0 "$elt_(1) coordinates 380.78 1279.63 7.90"

此外,对于每个文件,我只想保留每个元素一次(最后一次出现),我只想保留元素的索引和坐标后面的2个数字字段:

file1

0 649.08 1812.52 
1 366.2 1277.44 

更新: 所以从我得到的两个答案,我试图混合两个来得到我的答案

awk 'BEGIN{n=1}{x=$3;if(x>n*5){++n}{print > "file" n*5}}' file

for (i in file){awk 'BEGIN{}{if(($3+0)>max[$1])
{max[$1]=$3; line[$1]=$0}}END{for(i in line)
{print line[i];}}' file[i]}

现在第二部分(来自建议的uniq.awk),在单个文件上尝试时,只给出了一条唯一的行而不是所有唯一的行。

此外,for循环给了我一个错误,虽然这是我为它添加的全部

for (i in file){}

2 个答案:

答案 0 :(得分:1)

我写了两个awk脚本。当结合使用时,他们可以实现这一目标。像第一个(testsort.awk)那样召唤:

./testsort.awk test.txt

其中test.txt是输入文件。有一些诊断打印,实际输出位于名为file0file5等的文件中。

testsort.awk使用内部uniq.awk(均包含在下方)

testsort.awk

#! /bin/gawk -f

BEGIN{max=0;}{

  #use an array to map time values to first column value lists
  if($3 in arr){
    arr[$3]=arr[$3]" "$1;
  }else{
    arr[$3]=$1;
  }

  #use another array to store the whole line
  arr2[$3"_"$1]=$0;

  #keep track of the maximum time observed
  if(($3+0)>max){
    max=($3+0);
  }
}
END{

  #sort them into their files starting at zero
  for(i=0;i<max;i+=5){
    for(j in arr){
      split(arr[j],a," ")
      for(k in a){
        idx=j"_"a[k];
        num=(j+0);
        if(num>i && num<=i+5){
          output["file"i]=output["file"i]arr2[idx]"\n"
        }
      }
    }
  }

  #write the appropriate files
  for(i in output){
    print i;
    print output[i];
    if(length(output[i])>0){
      system("echo \""output[i]"\" |./uniq.awk|sort >"i);
    }
  }
}

uniq.awk

#! /bin/gawk -f

BEGIN{}{

  #find the maxes
  if(($3+0)>max[$1]){
    max[$1]=$3
    line[$1]=$0
  }

}
END{

  #write the appropriate files
  for(i in line){
    print line[i];
  }
}    

解决方案还取决于拥有shell实用程序sort

编辑:
在帖子中更改了输入文件的规范,现在我会这样做:

  1. $sed -e 's/[$]//g' < test.txt > test_new.txt摆脱原始输入中令人讨厌的美元符号

  2. $./testsort_new.awk test_new.txt

  3. 新文件testsort_new.awk

    #! /usr/bin/awk -f
    
    BEGIN{max=0;}{
    
      #use an array to map time values to first column value lists
      if($3 in arr){
        arr[$3]=arr[$3]" "$4;
      }else{
        arr[$3]=$4;
      }
    
      #use another array to store the whole line
      arr2[$3"_"$4]=$0;
    
      #keep track of the maximum time observed
      if(($3+0)>max){
        max=($3+0);
      }
    }
    END{
    
      #sort them into their files starting at zero
      for(i=0;i<max;i+=5){
        for(j in arr){
          split(arr[j],a," ")
          for(k in a){
            idx=j"_"a[k];
            num=(j+0);
            if(num>=i && num<i+5+1){
              output["file"i]=output["file"i]arr2[idx]"\n"
            }
          }
        }
      }
    
      #write the appropriate files
      for(i in output){
        print i;
        print output[i];
        if(length(output[i])>0){
          target=output[i];
          gsub("\"","\\\"",target);
          system("echo \""target"\" |./uniq_new.awk|sort -k4 >"i);
        }
      }
    }
    

    新文件uniq_new.awk

    #! /bin/awk -f
    
    BEGIN{}{
    
      #find the maxes
      if(($3+0)>max[$4]){
        max[$4]=$3
        line[$4]=$0
      }
    
    }
    END{
    
      #write the appropriate files
      for(i in line){
        print line[i];
      }
    }
    

    美元符号不会在输出中复制。

答案 1 :(得分:0)

根据输入无法获得确切的要求。试试以下。

awk 'BEGIN{n=1}{x=$3;if(x>n*5){++n}{print > "file" n}}' file