2013-02-24 29 views
5

Mam dwa pliki z liczby N kolumnachSubtructing n liczba kolumn z dwóch plików z AWK

plik1:

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

pliku Plik2:

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

chcę wyjście gdzie 1-cia wartość kolumny od pliku1 zostanie odjęta od 1. kolumny pliku 2, a następnie do kolumny N, jak pokazano poniżej:

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

Jak to zrobić, to skrypty AWK lub Perla w środowisku Linux?

Odpowiedz

1

coś takiego:

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); 

Aby uruchomić:

perl script.pl input1 input2 
+1

Zawsze umieścić '$' 'die' w ciąg tak wiesz, * dlaczego * open failed!. 'split ''' jest prawie zawsze tym, czego potrzebujesz, a nie 'split/\ s + /'. Pętla 'for' w stylu C jest zwykle lepiej napisana jako iterator listy, tutaj' dla mojego $ i (0 .. $ # v2) {...} ' – Borodin

1

Coś takiego może być? Obawiam się, że nie mogę przetestować tego kodu, ponieważ obecnie nie mam komputera.

Ten program oczekuje nazwy dwóch plików jako parametrów w wierszu poleceń, i wyświetla wyniki na STDOUT.

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

Przecinek po' push' nie należy do niego: -) –

+0

@ChrisCharley: Nie wiem jak to się wkradło! Dzięki. Naprawiony. – Borodin

2

To już zostało udzielone, ale dodam jeden liniowiec. Wykorzystuje paste, aby złączyć pliki, a awk odjąć:

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

Walidacja:

$ 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 

Wymaga oba pliki mają taką samą liczbę kolumn. Kolumny nieliczbowe powinny znajdować się w tej samej pozycji. Drukuje wartość w pierwszym pliku, jeśli nie jest liczbą, w przeciwnym razie drukuje różnicę.

+0

DZIĘKI ......... AWK również pomocne –

2

Spróbuj:

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

Oto jeden ze sposobów korzystania GNU awk.Biegać jak:

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

Treść 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 

Alternatywnie, oto jedna wkładka:

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 

Wyniki:

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 
> 

Alternatywnie umieścić to w pliku

#!/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]" " 
    } 
    } 

i wykonać jako:

awk -f file.awk file1 file2 
Powiązane problemy