複数のファイルの行を合計するためのAwkベースのソリューション

複数のファイルの行を合計するためのAwkベースのソリューション

次のファイルがいくつかあります。

ファイル1.dat:

1 1
1 3 4
5 9 10 11

ファイル2.dat:

3 0
8 9 0
3 9 2 4

通常、より多くの行があります(各行には、前の行よりも少ない列が含まれます)。上記の例を使用して、各ファイルの行を合計するハイブリッドbash / awkスクリプトを設計しました。

出力データ:

4 1
9 12 4
8 18 12 15

スクリプトは期待どおりに動作しますが、かなり遅いです。私のコンピュータでは、それぞれ10,000行の100個のファイルを処理するのに30分以上かかります。スクリプトは、すべてのファイルからn行目を収集するのにほとんどの時間を費やしているようです。file*.datawkコマンドに渡して私が行うことをする方法はありますか(下記参照)?

#!/bin/bash
ROWS=$1; shift
OUT_FILE=$1; shift
IN_FILE=("$@")

for i in `seq 1 1 ${ROWS}`; do
    # Get ith row from all input files
    for j in "${IN_FILE[@]}"; do
        tail -n+${i} ${j} | head -1 >> "temp.dat"
    done
    # Sum the rows 
    awk '{for (j=1;j<=NF;j++) a[j]+=$j} END {for (j in a) printf a[j] " "}' temp.dat >> ${OUT_FILE}
    echo >> ${OUT_FILE}
    rm temp.dat
done

上記の例に基づくスクリプトの使用法は次のとおりです。./RowSums.sh 3 out.dat file*.dat

ベストアンサー1

anypasteとanyを使用してくださいawk

$ cat tst.sh
#!/usr/bin/env bash

paste "${@}" |
awk -v numFiles="$#" '{
    numFldsPerFile = NF / numFiles
    for ( outFldNr=1; outFldNr<=numFldsPerFile; outFldNr++ ) {
        sum = 0
        for ( fileNr=1; fileNr<=numFiles; fileNr++ ) {
            inFldNr = outFldNr + (fileNr - 1) * numFldsPerFile
            sum += $inFldNr
        }
        printf "%d%s", sum, (outFldNr<numFldsPerFile ? OFS : ORS)
    }
}'

$ ./tst.sh file1.dat file2.dat
4 1
9 12 4
8 18 12 15

説明的な変数名と明示的なinFldNr計算によって、それが行うことを明確にすることができることを願っています。

おすすめ記事