次のデータファイルがあるとしましょう。
111 222 333
444 555 666
777 888 999
GNU Datamash を使用して、次のように各列の合計を計算できます。
cat foo | datamash -t\ sum 1 sum 2 sum 3
1332 1665 1998
データファイルの列数がわからない場合は、datamashを使用してこれをどのように実行しますか?
たとえば、フィールドセレクタcut
などの範囲終了記号をサポートしているので、この質問をします。-
答え1
不明な範囲を指定するオプションは表示されません。データ混合ハンドブック
このperl
単一のライナーをお試しください
$ perl -lane '$s[$_]+=$F[$_] for 0..$#F; END{print join " ", @s}' ip.txt
1332 1665 1998
-a
オプションは自動的に入力行をスペースに分割し、結果を@F
配列に保存します。for 0..$#F
配列を繰り返して$#F
最後の要素のインデックスを提供する$s[$_]+=$F[$_]
合計を@s
配列に保存すると、デフォルトでは初期値は0
数値コンテキストにあります。$_
各反復にはインデックス値があります。END{print join " ", @s}
すべての入力行が処理されたら、@s
スペースを区切り文字として使用して配列の内容を印刷します。
答え2
cols=$( awk '{print NF; exit}' foo); cat foo | datamash -t\ sum 1-$cols
または
cat foo | datamash -t\ sum 1-$( awk '{print NF; exit}' foo)
datamash
列範囲を指定する機能があるため、列数を計算し、その結果を範囲指定の一部として使用します。私のサンプルソリューションでは、awk
ファイルの最初の行を確認して終了しましたが、自分に適した他の項目を使用できます。出力に列番号を含むdatamash
関数自体がありますが、-check
その形式ではまだ関心のある特定の数値を解析する必要があります。
答え3
よくわかりませんが、解決策datamash
は次のとおりですawk
。
$ awk '{ for( col=1; col<=NF; col++ ) { totals[col]+=$col } } END { for( col=0; col<length(totals); col++ ) {printf "%s ", totals[col]}; printf "\n" } ' input
1332 1665 1998
awk
このスクリプトを読みやすくするには、次の手順を実行します。
{ // execute on all records
for( col=1; col<=NF; col++ ) {
totals[col]+=$col
};
}
END { // execute after all records processed
for( col=0; col<length(totals); col++ ) {
printf "%s ", totals[col]
};
printf "\n";
}
答え4
使用datamash
とbash
:
n=($(datamash -W check < foo)); datamash -W sum 1-${n[2]} < foo
出力:
1332 1665 1998
仕組み:
datamash -W check < foo
出力文字列「3つの行、3つのフィールド」。n=($(datamash -W check < foo))
文字列を配列としてロードします$n
。私たちはフィールド数、すなわち${n[2]}
。datamash -W sum 1-${n[2]} < foo
残りは完了しました。
これは次の方法で行うこともできます。POSIXシェルprintf
は配列の代わりに複雑な型の文字列を使用しますが、より粗雑です。
datamash -W sum 1-$(printf '%0.0s%0.0s%s%0.0s' $(datamash -W check < foo)) < foo
これはシェルツールを使用して行うこともできます。
datamash -W sum 1-$(head -1 foo | wc -w) < foo