2

我有要在 unix 中重新格式化的数据,将第 2-3 列创建一个新列(在示例中称为 when ),但在弄清楚如何执行此操作时遇到了麻烦。在不更改作为数据标识符的第 4-7 列的情况下,我想打印第 2 列的第 3 列中指定的次数,然后打印一个值(在本例中为 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
4

3 回答 3

1

这是使用awk. 它使用未修改的输入文件。像这样运行:

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

内容script.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
    }
}

结果:

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
于 2012-11-26T08:23:25.213 回答
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

于 2012-11-25T01:00:33.070 回答
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
> 
于 2012-11-26T06:22:30.343 回答