同じ識別子を持つすべての行列を合計するsed
コマンドがあるかどうかを知りたいです。awk
たとえば、私のファイルはdata.txt
次のようになりますが、約1800のデータ列と約1400の行が含まれています。
ABCD:1234 1.23 0.23 0.83 0
ABCD:1234 0 1.10 0.21 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 1.22 0 1.84 9.21
IJKL:9999 1.44 0 12.94 0
IJKL:9999 1.32 0 24.12 2.43
後でコマンドがどのように見えるようにしたいか:
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64
awk
これがsed
(私は生物学者であり、まだUnixの基礎を学んでいます)で動作するかどうかわかりません。どんな助けでも大変感謝します。
答え1
awk
入力ファイルまたは結果テーブル全体をメモリに保存しないスクリプト:
FNR == 1 { for(i = 1; i <= NF; i++) a[i] = $i; next }
$1 == a[1] { for(i = 2; i <= NF; i++) a[i] += $i; next }
{
printf "%s", a[1]; a[1] = $1;
for(i = 2; i <= NF; i++) { printf "\t%s", a[i]; a[i] = $i };
printf "\n";
}
END {
printf "%s", a[1];
for(i = 2; i <= NF; i++) printf "\t%s", a[i];
printf "\n";
}
実行してください:
awk -f script.awk data.txt
結果:
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64
注:実際には動作しますsed
が、まもなくそうすることはありません。バラよりここ理由を調べてください。
答え2
代替ソリューションperl
$ perl -nale '
if(!$seen{$F[0]}++)
{
print join "\t", @a if @a;
@a = @F[0..$#F];
}
else
{
$a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' data.txt
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64
-a
入力行をスペースに分割して配列@F
に保存します。- 行の最初のフィールドはハッシュ変数のキーとして使用されます
%seen
。キーが見つからない場合は、配列@a
の内容が印刷され(空でない場合)、新しい行のフィールドが配列に割り当てられます。 - キーがすでに存在する場合は、配列の内容(2番目のフィールドから最後まで)を現在の行の内容に追加します。
@a
最後の項目を処理するには、ファイルの終わりに達したら配列の内容を再印刷します。
重複質問の場合:最初の列に同じ項目がある場合は、Linuxですべての列を別々に追加します。
$ perl -nale '
if(!$seen{$F[0]}++)
{
print join "\t", @a if @a;
@a = @F[0..$#F];
}
else
{
$a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' filename.txt
AC1481523 6 6 6 6
AC1481676 6 5 6 8
配列ハッシュを構築し、最後にハッシュを印刷するソリューション:
$ perl -nale '
if($h{$F[0]})
{
$h{$F[0]}[$_] += $F[$_] foreach (1..$#F)
}
else
{
$h{$F[0]} = [@F]
}
END { print join "\t",@{$h{$_}} foreach sort keys %h }
' data.txt
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64