awk は、あるファイルからヘッダーを読み取り、分割して別のファイルで使用します。

awk は、あるファイルからヘッダーを読み取り、分割して別のファイルで使用します。

私は列166以降の列ヘッダーを取得し、それを各後続の行に印刷するawkスクリプトを使用しています。

前任者。

col165    col166    col167
a         1         2
b         3         4
c         5         6

これになる--

col165    col166    col167
a         col166|1         col167|2
b         col166|3         col167|4
c         col166|5         col167|6

しかし、私が作業しているファイルはかなり大きく(約160万行)、処理に約1.5時間かかります。

プロセスを高速化するために、大容量ファイルを100,000行に分割し、gnuを使用してparallel各ファイルを個別に処理する方法を考えました。しかし、ファイルのヘッダーを取得してヘッダーをインポートするために使用するスクリプトに問題が発生しました。ヘッダを指定するために別のファイルを使用したいと思います。それ以外の場合は、各分割ファイルにヘッダーを追加する必要があります(それ自体は面倒です)。

私が使用するコードは -

awk 'BEGIN { FS="\t";OFS="\t" };
     NR == 1 { split($0, headers); print; next }
     {for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1' input > output

column_headersファイルを使用してタイトルを指定したいと思います。可能ですか?

次のコードを試しましたが、うまくいかず、コードが正しいかどうかはわかりません。

awk -v head='$(cat column_headers)' 'BEGIN{ FS="\t";OFS="\t" };
        NR == 1 { split($head, headers); print; next }
        {for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1' input > output

私が何か間違っているような気がしますが、何なのかよくわかりません。私が受けることができるどんな助けにも感謝します。

編集:ありがとう。実際、長期的な犯人だったチェーンのもう一つの命令を逃した。

@Ole Tangeが述べたようにコマンドを使用しましたが、少し修正しました。

time cat input_1|parallel -k -q -j 24 --tmpdir tmp/ --block 900M --pipe awk -f culprit_script > output

スクリプトはデフォルトで各フィールドを分割し、値に応じて削除/保持します。

最初のコマンドを実行するのに約15〜20分かかり、2番目のスクリプトは1時間かかりました。並列性と24スレッドを活用して7分で完了!最初のコマンドにも並列性を使用すると思います。

皆様のご意見やご提案ありがとうございます!

答え1

実際には答えではありませんが、大きすぎて書式が必要なのでコメントできないので...

1.6Mは多くの行数ではありません。おっしゃるとおり、1時間あたり100万行が表示されます。大規模に遅い場合は、1分あたり100万行がより合理的です。たとえば、次のスクリプトを実行して、1行に300列の1,600,000行のファイルを作成しました。

$ awk -v n=1600000 -v c=300 -v OFS='\t' 'BEGIN{for (j=1;j<=c;j++) printf "col%s%s",j,(j<c?OFS:ORS); for (i=1;i<=n;i++) for (j=1;j<=c;j++) printf "%s%s",j,(j<c?OFS:ORS)}' > file

次に、定期的にスクリプトを実行して問題のファイルを変換します。

$ time awk 'BEGIN{FS=OFS="\t"} NR==1{split($0, headers); print; next} {for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1' file > out

real    1m22.569s
user    1m17.971s
sys     0m4.359s

したがって、実行時間は1.5時間ではなく約82秒です。

答え2

GNU Parallelの場合:

#!/bin/bash

do_block() {
    awk 'BEGIN{FS=OFS="\t"}
     NR==1{split($0, headers); next}
     {for (i=166;i<=NF;i++) $i=headers[i] "|" $i } 1'
}
export -f do_block

# Non-parallel version
cat file | head -n1 > out1
time cat file | do_block >> out1

# Parallel version
cat file | head -n1 > out2
time parallel -k --pipepart --block -30 -a file --header : do_block >> out2

私の4コアCPUでは、並列バージョンは約3倍高速です。

関連情報