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

を使用する 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 に答える