1

数百万の行と数千の列/フィールドを含む入力ファイルがあります。誰かが私に説明できますか、同じ出力を生成する以下の2つのawkメソッドが、CPU実行時間の点で大きく異なるのはなぜですか?

175.0秒:

awk 'BEGIN{FS=":| "}NR>1{field1=$1;field2=$2;$1="";$2="";print field1":"field2,field1":"field2,field2,$0}' file_in > file_out

19.7秒:

cat file_in | awk 'BEGIN{FS=":"}NR>1{print $1,$2}' | awk '{print $1":"$2,$1":"$2,$0}' | cut -d " " -f 3 --complement > file_out

これは、数百の列/フィールドを持つ1つのfile_inの2行目と3行目です(行間に改行はありません)。

1:1000071 C T 1 0 0 1 0 0
1:1000759 C T 1 0 0 0 1 0

file_outの対応する行は次のとおりです。

1:1000071 1:1000071 1000071 C T 1 0 0 1 0 0
1:1000759 1:1000759 1000759 C T 1 0 0 0 1 0
4

2 に答える 2

6

これらの2つのステートメント:

$1="";$2=""

awkが各レコードを2回再コンパイルする原因になっています。それぞれに数百万の行と数千のフィールドがあることを考えると、それが影響を与えると思います。

代表的なサンプル入力と期待される出力の数行を表示すると、簡潔かつ効率的にそれを行う方法を示すことができます。

あなたがしているのは次のような行を変換することだけのように見えます:

1:1000071 C T 1 0 ...
1:1000759 C T 1 0 ...

このような行に:

1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...

もしそうなら、あなたがする必要があるのは:

awk '{x=$1; sub(/[^:]+:/,x" "x" ")}1' file

または、これは1行の単純な置換であるため、sedでも処理できます。

sed 's/\([^:]*:\)\([^ ]*\)/\1\2 \1\2 \2/' file

見て:

$ cat file
1:1000071 C T 1 0 ...
1:1000759 C T 1 0 ...

$ awk '{x=$1; sub(/[^:]+:/,x" "x" ")}1' file
1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...

$ sed 's/\([^:]*:\)\([^ ]*\)/\1\2 \1\2 \2/' file
1:1000071 1:1000071 1000071 C T 1 0 ...
1:1000759 1:1000759 1000759 C T 1 0 ...

ああ、でもサンプル入力は2行目以降だとおっしゃっていたので、ヘッダー行かスキップするものがあると思います。それは次のようになります:

awk 'NR>1{x=$1; sub(/[^:]+:/,x" "x" ");print}' file

sed -n '2,$s/\([^:]*:\)\([^ ]*\)/\1\2 \1\2 \2/p' file

最後に、サンプル入力に示されているように、すべての行が「1:」で始まる場合に、より効率的な代替のawkソリューションを次に示します。

awk 'NR>1{print $1, $1, substr($0,3)}' file
于 2013-02-17T11:05:51.503 に答える
0

これは依然として最速のソリューションです。

  cat file_in | awk 'BEGIN{FS=":"}NR>1{print $1,$2}' | awk '{print $1":"$2,$1":"$2,$0}' | cut -d " " -f 3 --complement > file_out
于 2013-03-03T19:32:35.390 に答える