awkで「システム」コール(シェルエスケープ)を使用して大容量ファイルを処理するときのパフォーマンスの向上

awkで「システム」コール(シェルエスケープ)を使用して大容量ファイルを処理するときのパフォーマンスの向上

次のように非常に大きなファイルを処理するawkスクリプトがあります。

K1353 SF3987.7PD833391.4  KARE
K1353 SF3987.2KD832231.4 MEAKE
K1332 IF4987.7RP832231.2 LEAOS
K1329 SF2787.7KD362619.3 NEDLE
K1353 SK3K84.3KD832231.3 PQAKM

このファイルは固定列ファイルです。

スクリプトは現在、一部の抽出されたフィールドでプログラムを実行し、それを元の場所に戻します。私はawkを使用しています。パフォーマンスは単純なawkスクリプトほど良くありません。ボトルネックはコマンドのシステムコールのようです。

デモの目的で「rev」を含めましたが、実際にはこれらのフィールドを変換するカスタムプログラムを実行します。このコマンドはSTDINを介して2つの引数のみを受け入れるか、ファイルから読み取ることができますが、通常は非常に高速に実行されます。実際の実行者はサードパーティのアプリケーション/バイナリであり、どのように機能するかについての詳細がわかりません。

BEGIN {
  csmok="rev"
}

{
  type = substr($0,1,1)

  if (type == "K") {

    RX=substr($0,6,9)
    RY=substr($0,15,9)

    cmd=sprintf("echo %s %s | %s", RX, RY, csmok)
    cmd | getline output
    close(cmd)
    split(output,k," ")
    sub(RX,k[1])
    sub(RY,k[2])
    print
  }

}

次のように実行してください。

$ awk -f process.awk file.dat

私が作業しているファイルは時々900,000行に達する非常に大きなファイルなので、実行に長い時間がかかります。速度が遅いと system()/exec 呼び出しが発生することを意味します。

ランタイムをどのように改善できますか?

抽出されたすべてのフィールドを1つのコマンドにリンクするなど、スクリプトを一度実行させる方法を検討しました。

echo -e "SF3987.7 PD833391.4\nSF3987.2 KD832231.4\nIF4987.7 RP832231.2" | rev

または

rev << EOF
SF3987.7 PD833391.4
SF3987.2 KD832231.4
IF4987.7 RP832231.2
EOF

これを達成する方法がわからず、処理された出力が残っていますが、ファイルの右側の列に戻す方法はわかりません。

出力は入力と非常によく似ている必要があり、抽出されたフィールドのみが外部プログラムによって翻訳されます。

K1353.193338DP7.7893FS4  KARE
K1353.132238DK2.7893FS4 MEAKE
K1332.132238PR7.7894FI2 LEAOS
K1329.916263DK7.7872FS3 NEDLE
K1353.132238DK3.48K3KS3 PQAKM

または、awkを使用せずにGNU / Linux環境でこれを行う他の方法を知りたいです。

ベストアンサー1

入力の各行(または少なくとも「K」で始まる各行)の長さが正確に29文字であると仮定すると、次のようにして希望の出力を複製できます。

回転速度ファイル名|貼り付けファイル名- |アイク
{
        if (substr($0,1,1) == "K") {
                印刷 substr($0,1,5) substr($0,39,17) substr($0,24,7)
        }
} '

これ

  • rev入力ファイル全体を一度に実行します。
    • どうやらこれを処理します。すべて外部プログラムを介してファイルに行を追加します。パイプラインを作成し、各行に対して一度に外部プログラムを呼び出すオーバーヘッドが心配です。これらの懸念に基づいて、これは慎重なアプローチだと思います。ただし、入力に「K」で始まる行が数行しかなく、他の行を処理するのに費用がかかる場合は、変更が必要になることがあります。
    • rev各入力ラインは正確に1ラインの出力を生成します。私の解決策は外部プログラムの動作に依存します。
  • paste入力ファイルをの出力と1行ずつ結合します(使用)rev。サンプルデータの場合、次のようになります。
    K1353 SF3987.7PD833391.4 カレラック 4.193338DP7.7893FS 3531K
    K1353 SF3987.2KD832231.4 ミックエカム 4.132238DK2.7893FS 3531K
    K1332 IF4987.7RP832231.2 LEAOS SOAEL 2.132238PR7.7894FI 2331K
    K1329 SF2787.7KD362619.3ピン ELDEN 3.916263DK7.7872FS 9231K
    K1353 SK3K84.3KD832231.3 PQAKM MKAQP 3.132238DK3.48K3KS 3531K
  • awk上記の行をお読みください。各ファイルには、入力ファイルの1行とrevその行の出力が含まれています。  awk次に、必要な各部分を組み合わせます。


<ホアンジャンダム>

あなたの質問は少し一貫していません。サンプル入力データを受信すると

K1353 SF3987.7PD833391.4  KARE
K1353 SF3987.2KD832231.4 MEAKE
K1332 IF4987.7RP832231.2 LEAOS
K1329 SF2787.7KD362619.3 NEDLE
K1353 SK3K84.3KD832231.3 PQAKM

このawkスクリプトにフィードを提供します。

{
    RX=substr($0,6,9)
    RY=substr($0,15,9)
    printf("/%s/%s/\n", RX, RY)
}

私は次のような結果を得ます。

/ SF3987.7/PD833391./
/ SF3987.2/KD832231./
/ IF4987.7/RP832231./
/ SF2787.7/KD362619./
/ SK3K84.3/KD832231./

値には、RX最初の列と2番目の列の間のスペースが含まれ、RY値はするいいえ2番目の列値の最後の文字を含みます(つまり、2番目の点の後の数字)。これは本当に言うことができません。

        sprintf("echo %s %s | %s", RX, RY, csmok)

ステートメントはinの初期スペースをRX失います。

混乱してもはい質問の一番下の予想結果と一致しますが、上記の5つの段落とは異なります。

echo -e "SF3987.7 PD833391.4\nSF3987.2 KD832231.4\nIF4987.7 RP832231.2" | rev

つまり、送信する文字列の2番目の点の後に数字を含めますrev

そして 2つの重複しないが連続した部分文字列を抽出し、コマンドから分割します$0。これはすべて不要です。私はあなたの結果を複製することができますoutputrev

BEGIN {
  csmok="rev"
}

{
  type = substr($0,1,1)

  if (type == "K") {

    RXY=substr($0,6,18)

    cmd=sprintf("echo %s | %s", RXY, csmok)
    cmd | getline output
    close(cmd)
    sub(RXY,output)
    print
  }

}

つまり、文字列$0 を分割せずに文字列から18文字の部分文字列を抽出しますoutput

あなたの質問のデータが妥当で内部的に一貫しているようにしてください。


つまり、合理的な答えを得るために、正確な質問のすべての詳細を正確に投稿することが必ずしも必要ではないことを理解しているようです。これらの精神は、質問の完全性を損なうことなく、質問を理解しやすくします。あなたのデータが目を痛めます。

  • 各行の最初の3文字は「K13」です。これにより、さまざまなキャラクターを見るのが難しくなります。
  • 5行のうち3行の最初の5文字(つまり、最初の列の値全体)は「K1353」です。
  • 2番目の列の値は、18文字の長さの文字、数字、点が無意味に混在しているため、読みやすく理解しにくいです。
  • 2番目の列の値を確認してください。
    • 5つの要素のうち4つが「S」で始まります。
    • 「SF」で始まる3行です。
    • 3行目から3番目の文字は「3」です。
    • 4行のうち10番目の文字は「D」です。
    • 3行のうち9番目と10番目の文字は「KD」です。
    • 4行目の11番目と12番目の文字は「83」、16番目の文字は「1」です。
    • 3行の文字11-16は「832231」です。

次のサンプルデータを公開することをお勧めします。

ant 12345.hill  Adam
bat 31416.cave Bruce
cat 13579.meow Felix
dog 32768.bark Angus

このような入力データを使用すると、目的の出力に「tac」、「97531」、「woem」、「xileF」などの文字列を含めることができます。ソースを見つけるために虫眼鏡を持って6〜8分を消費する必要がある「132238DK2」とは、ほぼ「単語検索」パズルの1つに似ています。 (「KD832231」が2回表示されるため、「132238DK」のみ追跡可能ではありません。)

</rant>

おすすめ記事