使用AWK从两个文件中分解n个列

我有两个N列数的文件

文件1:

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

文件2:

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

我想要一个输出从File1的第一列值将被从File2的第一列中减去,这样直到列N如下所示:

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

如何在Linux环境中执行AWK或Perl脚本?

Solutions Collecting From Web of "使用AWK从两个文件中分解n个列"

像这样的东西:

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

跑步:

  perl script.pl input1 input2 

这已经得到了答复,但我会添加一行。 它使用paste来连接文件, awk减去:

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

验证:

 $ 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 

它要求两个文件具有相同的列数。 非数字列应位于相同的位置。 如果是非数字,它将在第一个文件中打印值,否则打印差异。

尝试:

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

这是使用GNU awk的一种方法。 运行如下:

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

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 

另外,这里是一行:

 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 

结果:

 A -1 0 -1 B 1 0 0 
 awk 'FNR==NR{for(i=2;i<=NF;i++)a[FNR"-"i]=$i;next}{printf "\n"$1" ";for(i=2;i<=NF;i++){printf $ia[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 $ia[FNR"-"i]" "}}' file1 file2 A 1 0 1 B -1 0 0 > 

或者把它放在一个文件中

 #!/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 $ia[FNR"-"i]" " } } 

并执行如下:

 awk -f file.awk file1 file2 

也许这样的事情? 恐怕我无法测试这个代码,因为我目前没有电脑。

这个程序预计这两个文件的名称作为命令行上的参数,并将结果输出到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"; }