同一の識別子を持つ行のすべての列を合計できる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の基礎を学んでいます)。どんな助けでも大歓迎です。
入力ファイルまたは結果テーブル全体をメモリに保持しない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
でそれを行うことが可能です。しかし、あなたはすぐにそれをすることはないでしょう。理由については、 ここ を参照してください。
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
配列の内容が空でない場合は出力し、配列に改行のフィールドを割り当てます。@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