2013-02-24 13 views
5

Ich habe zwei Dateien mit N Anzahl der SpaltenSubtructing n Anzahl der Spalten aus zwei Dateien mit AWK

File1:

A 1 2 3 ....... Na1 
B 2 3 4 ....... Nb1 

File2:

A 2 2 4 ....... Na2 
B 1 3 4 ....... Nb2 

Ich mag eine Ausgabe in der ersten Der Spaltenwert von Datei1 wird von der ersten Spalte von Datei2 subtrahiert und auf diese Weise bis Spalte N wie unten gezeigt:

A -1 0 -1 ........ (Na1-Na2) 
B 1 0  0 ........ (Nb1-Nb2) 

Wie ist dies AWK oder Perl-Skripting in Linux-Umgebung?

Antwort

1

Etwas wie folgt aus:

use strict; 
use warnings; 

my (@fh, @v); 
for (@ARGV) { 
    open (my $handle, "<", $_) or die ("$!: $_"); 
    push @fh, $handle; 
} 
while (@v = map { [split ' ', <$_> ] } @fh and defined shift @{$v[0]}) { 
    print join(" ", (shift @{$v[1]}, map { $_ - shift(@{$v[1]}) } @{$v[0]})), "\n"; 
} 
close $_ for (@fh); 

auszuführen:

perl script.pl input1 input2 
+1

setzen immer '$' im 'die' String, so dass Sie wissen, * warum * die offene failed!. 'split '' 'ist fast immer was du willst, anstatt' split/\ s +/'. Die 'for'-Schleife im C-Stil wird normalerweise besser als Listeniterator geschrieben, hier' für meine $ i (0 .. $ # v2) {...} ' – Borodin

1

So etwas wie vielleicht das? Ich fürchte, ich kann diesen Code nicht testen, da ich zur Zeit keinen PC zur Hand habe.

Dieses Programm erwartet die Namen der beiden Dateien als Parameter in der Befehlszeile und gibt die Ergebnisse an STDOUT aus.

use strict; 
use warnings; 
use autodie; 

my @fh; 
for my $filename (@ARGV) { 
    open my $fh, '<', $filename; 
    push @fh, $fh; 
} 

until (grep eof $_, @fh) { 
    my @records; 
    for my $fh (@fh) { 
    my $line = <$fh>; 
    chomp $line; 
    push @records, [ split ' ', $line ]; 
    } 

    $records[0][$_] -= $records[1][$_] for 1 .. $#{$records[0]}; 
    print "@{$records[0]}\n"; 
} 
+0

Das Komma nach' push' gehört nicht dorthin: -) –

+0

@ChrisCharley: Ich weiß nicht, wie das reingeschlichen ist! Vielen Dank. Fest. – Borodin

2

Dies wurde bereits beantwortet, aber ich werde einen Einzeiler hinzufügen. Es verwendet paste, um die Dateien zu verketten, und awk zu subtrahieren:

paste file{1,2} | awk '{for (i=1;i<=NF/2;i++) printf "%s ", ($i==$i+0)?$i-$(i+NF/2):$i; print ""}' 

Validierung:

$ cat file1 
A 1 2 3 4 5 
B 2 3 4 5 6 

$ cat file2 
A 2 2 4 10 12 
B 1 3 4 3 5 

$ paste file{1,2} | awk '{for (i=1;i<=NF/2;i++) printf "%s ", ($i==$i+0)?$i-$(i+NF/2):$i; print ""}' 
A -1 0 -1 -6 -7 
B 1 0 0 2 1 

Es erfordert beide Dateien die gleiche Anzahl von Spalten zu haben. Nicht numerische Spalten sollten sich an der gleichen Position befinden. Es druckt den Wert in der ersten Datei, wenn nicht numerisch, andernfalls wird die Differenz gedruckt.

+0

DANKE ......... AWK auch hilfreich –

2

Versuchen:

awk '{split($0,S); getline<f; for(i=2; i<=NF; i++) $i-=S[i]}1' OFS='\t' f=file1 file2 
2

Hier ist eine Möglichkeit GNU awk verwenden.Lauf wie:

awk -f script.awk File2 File1 | rev | column -t | rev 

Inhalt von script.awk:

FNR==NR { 
    for(i=2;i<=NF;i++) { 
     a[$1][i]=$i 
    } 
    next 
} 

{ 
    for(j=2;j<=NF;j++) { 
     $j-=a[$1][j] 
    } 
}1 

Alternativ ist hier die Einzeiler:

awk 'FNR==NR { for(i=2;i<=NF;i++) a[$1][i]=$i; next } { for(j=2;j<=NF;j++) $j-=a[$1][j] }1' File2 File1 | rev | column -t | rev 

Ergebnisse:

A -1 0 -1 
B 1 0 0 
2
awk 'FNR==NR{for(i=2;i<=NF;i++)a[FNR"-"i]=$i;next}{printf "\n"$1" ";for(i=2;i<=NF;i++){printf $i-a[FNR"-"i]" "}}' file1 file2 
> cat file1 
A 1 2 3 
B 2 3 4 
> cat file2 
A 2 2 4 
B 1 3 4 
> awk 'FNR==NR{for(i=2;i<=NF;i++)a[FNR"-"i]=$i;next}{printf "\n"$1" ";for(i=2;i<=NF;i++){printf $i-a[FNR"-"i]" "}}' file1 file2 
A 1 0 1 
B -1 0 0 
> 

diese Alternative in einer Datei als

#!/usr/bin/awk 
FNR==NR{ 
    for(i=2;i<=NF;i++) 
    a[FNR"-"i]=$i;next 
    } 
    { 
    printf "\n"$1" "; 
    for(i=2;i<=NF;i++) 
    { 
    printf $i-a[FNR"-"i]" " 
    } 
    } 

und ausführen setzen:

awk -f file.awk file1 file2 
Verwandte Themen