2012-11-25 46 views
2

我有要在UNIX中重新格式化的数据,以2-3列创建一个新列(在本示例中调用时),但无法计算了解如何做到这一点。在不改变列4-7的情况下,它们一起作为数据的标识符,我想在列3中列出指定次数的列2,然后输出一个值(本例中为31)N(=每个标识符的列1 )减去(每个标识符的列3的总和)次数。因此,重新格式化的数据每个标识符总共有N行。 的数据开始看起来像这样:一列的打印值在另一列中指定的次数

N time awake line sex temp rep 
9 15 1 188 f 25 1 
9 20 1 188 f 25 1 
9 21 1 188 f 25 1 
9 28 1 188 f 25 1 
10 12 1 205 m 25 1 
10 14 3 205 m 25 1 
10 16 1 205 m 25 1 
10 18 1 205 m 25 1 
10 19 2 205 m 25 1 
10 22 1 205 m 25 1 
10 24 1 205 m 25 1 

重新格式化数据应该有希望是这个样子:

line sex temp rep when 
188 f 25 1 15 
188 f 25 1 20 
188 f 25 1 21 
188 f 25 1 28 
188 f 25 1 31 
188 f 25 1 31 
188 f 25 1 31 
188 f 25 1 31 
188 f 25 1 31 
205 m 25 1 12 
205 m 25 1 14 
205 m 25 1 14 
205 m 25 1 14 
205 m 25 1 16 
205 m 25 1 18 
205 m 25 1 19 
205 m 25 1 19 
205 m 25 1 22 
205 m 25 1 24 

我的猜测是,它需要某种循环,我觉得伪会看起来像这样:

for (each columns 4-7) 
    tot = (column 1) 
    rem = tot - sum (column 3) 
    for (i=0; i <= column 3; i++) 
     print column 2"\n" 
    for (j=0; i <= rem; j++) 
     print "31\n" 

任何帮助非常感谢!

编辑添加: 我试过从@mvp下面修改perl代码,但它不是很正确。我使用awk将原始列4-7重新格式化为一个名为id的字段(和变量)。任何意见?

print "id  when\n"; # output header 
my $temp='188.f.25.1'; 
my $count; 
my $rest; 
my $total; 
while(my $input = <>) { 
    my ($n, $time, $awake, $id) 
     = split /\s+/, $input; # read each line 
    next if $n eq 'N'; # skip input header line 
    if ($id eq $temp) { 
     $count++; 
     for (1..$awake) {print "$id  $time\n";} 
     $total = $n; 
     next; 
    } 
    else { 
     $rest=$total-$count; 
     for (1..$rest) {print "$temp 31\n";} 
    } 
    $count=0; 
    $temp = $id; 
    next; 
} 

而修改的输入文件:

N  time awake line.sex.temp.rep 
9  15  1  188.f.25.1 
9  20  1  188.f.25.1 
9  21  1  188.f.25.1 
9  28  1  188.f.25.1 
10  12  1  205.m.25.1 
10  14  3  205.m.25.1 
10  16  1  205.m.25.1 
10  18  1  205.m.25.1 
10  19  2  205.m.25.1 
10  22  1  205.m.25.1 
10  24  1  205.m.25.1 
10  10  1  206.m.25.1 
10  14  1  206.m.25.1 
10  18  1  206.m.25.1 
10  20  1  206.m.25.1 
10  24  1  206.m.25.1 
10  26  1  206.m.25.1 
10  27  1  206.m.25.1 
10  28  2  206.m.25.1 
+0

所以,你想要的输出是什么? – Kenosis

+0

@Kenosis期望的输出实际上是相同的,除了最初初始期望的输出的前四列将是一个由句点分隔的单个字段,我将使用awk重新分离(由于我是一个新手,无法真正弄清楚如何一次完成这一切) – suegene

回答

1

下面是使用awk的一种方式。它使用未修改的输入文件。的script.awk

awk -f script.awk file{,} | column -t 

内容:

BEGIN { 
    print "line sex temp rep when" 
} 

FNR==NR && NR>1 { 
    a[$4,$5,$6,$7]+=$3 
    next 
} 

FNR>1 { 
    for (i=1;i<=$3;i++) { 
     print x=($4 FS $5 FS $6 FS $7), $2 
     a[$4,$5,$6,$7]-- 
     var++ 
    } 

    if (a[$4,$5,$6,$7]==0) { 
     for (i=1;i<=$1-var;i++) { 
      print x, "31" 
     } 
     var=0 
    } 
} 

结果:像运行

line sex temp rep when 
188 f 25 1 15 
188 f 25 1 20 
188 f 25 1 21 
188 f 25 1 28 
188 f 25 1 31 
188 f 25 1 31 
188 f 25 1 31 
188 f 25 1 31 
188 f 25 1 31 
205 m 25 1 12 
205 m 25 1 14 
205 m 25 1 14 
205 m 25 1 14 
205 m 25 1 16 
205 m 25 1 18 
205 m 25 1 19 
205 m 25 1 19 
205 m 25 1 22 
205 m 25 1 24 

另外,这里是一个班轮:

awk 'BEGIN { print "line sex temp rep when" } FNR==NR && NR>1 { a[$4,$5,$6,$7]+=$3; next } FNR>1 { for (i=1;i<=$3;i++) { print x=($4 FS $5 FS $6 FS $7), $2; a[$4,$5,$6,$7]--; var++ } if (a[$4,$5,$6,$7]==0) { for (i=1;i<=$1-var;i++) print x, "31"; var=0 } }' file{,} | column -t 
用新的数据格式
+0

太棒了,非常感谢! – suegene

+0

你会介意评论这是什么吗?:a [$ 4,$ 5,$ 6,$ 7] - – suegene

+0

@suegene:不是问题; 'a [4美元,5美元,6美元,7美元] - '简单地递减(一个)多维数组保持列4,5,6和7. – Steve

0

这是我会怎么做它用Perl:

保存为myscript.pl

#!/usr/bin/perl 

use strict; 
use warnings; 

print "line sex temp rep when\n"; # output header 
while(my $input = <>) { 
    my ($n, $time, $awake, $line, $sex, $temp, $rep) 
     = split /\s+/, $input; 
    next if $n eq 'N'; # skip input header line 
    for (1..$awake) { 
     print "$line $sex $temp $rep $time\n"; 
    } 
} 

称呼其为myscript.pl <a.txt >b.txt

+0

你介意扩大你的答案,包括如何读取数据文件(我们可以调用是a.txt)并输出到重新格式化的文件(b.txt )? – suegene

+0

新增用法,请参阅我修正的答案 – mvp

+0

我已经运行了该脚本,它看起来像是迄今为止的部分解决方案。它没有解决在重新格式化文件的最后一列中填充行的值为“31”的问题。这是我得到的输出(对不起,不知道如何让它正确显示):205 m 25 1 14 205 m 25 1 16 205 m 25 1 18 205 m 25 1 19 205米25 1 19 205米25 1 22 205米25 1 24 206米25 1 10 206米25 1 14 206米25 1 18 206米25 1 20 206米25 1 24 206米25 1 26 206 m 25 1 27 206 m 25 1 28 206 m 25 1 28 – suegene

0
perl -F -lane 'if($.==1){print "@F[3,4,5,6,1]"}for($i=0;$i<$F[2];$i++){print "@F[3,4,5,6,1]"}' your_file 

,或者您也可以使用此:

perl -F -lane 'for($i=0;($i<$F[2])||($.==1);$i++){print "@F[3,4,5,6,1]";if($.==1){last}}' your_file 

如下测试:

> cat temp 
N  time awake line sex  temp rep 
9  15  1  188  f  25  1 
9  20  1  188  f  25  1 
9  21  1  188  f  25  1 
9  28  1  188  f  25  1 
10  12  1  205  m  25  1 
10  14  3  205  m  25  1 
10  16  1  205  m  25  1 
10  18  1  205  m  25  1 
10  19  2  205  m  25  1 
10  22  1  205  m  25  1 
10  24  1  205  m  25  1 

执行:

> perl -F -lane 'if($.==1){print "@F[3,4,5,6,1]"}for($i=0;$i<$F[2];$i++){print "@F[3,4,5,6,1]"}' temp 
line sex temp rep time 
188 f 25 1 15 
188 f 25 1 20 
188 f 25 1 21 
188 f 25 1 28 
205 m 25 1 12 
205 m 25 1 14 
205 m 25 1 14 
205 m 25 1 14 
205 m 25 1 16 
205 m 25 1 18 
205 m 25 1 19 
205 m 25 1 19 
205 m 25 1 22 
205 m 25 1 24 
> 
相关问题