AWKスクリプトのwhile関数に関する問題

AWKスクリプトのwhile関数に関する問題

私はシミュレーションで評価ファイルを処理するために使用する見苦しいスクリプトを持っています。それはひどいようです。いいえ、私はコーダーではなく、通常は動作しますが、現在は動作しません。

明らかに、スクリプトは通常複数の入力ファイルを繰り返し、私のMacとシミュレーションを実行しているクラスタで動作します。 Ubuntuサーバーを実行しているVPSで実行しようとすると、奇妙な出力が生成されます。この問題を解決する方法がわかりません。

完全なスクリプトは次のとおりです。

#!/usr/bin/awk -f
FNR==1 && NR!=1 { endfile(); avgLT=totFrames=avgLTsq=avgFramessq=denom=0 }
FNR==1 { out1="analLT_"FILENAME; out2="sumLT_"FILENAME; out3="reportLT.txt"; print "-> Input file is: "FILENAME >> out3; next
       }
FNR==1 { next }

{
   avgLT+=$4; totFrames+=$5; ++denom;
   printf "%10.4f %10.1f\n",$4,$5 > out1
  }

END { endfile() }
function endfile()
{
  x="\nNO DATA POINTS IN INPUT => NO HYDROGEN BONDS DETECTED!"
  if (avgLT==0 && denom==0) {
    print x > out1; print x > out2; print x"\n\n----------------------------------------\n" >> out3;
    close(out1); close(out2); close(out3); return
  }
  if (avgLT>0) {
    avgAvgLT=avgLT/denom
    avgFrames=totFrames/denom
    while ((getline<out1)>0) {
      avgLTsq+=(($1-avgAvgLT)^2)
      avgFramessq+=(($2-avgFrames)^2)
    }
  close(out1)
    printf "\n   Summary data for hbond lifetime analysis:\n\n" > out2
    printf "   Summed Avg Lifetime:    %10.4f\n",avgLT > out2
    printf "   Average Lifetime:       %10.4f\n",avgAvgLT > out2
    printf "      Summed Frames:  %10.0f\n",totFrames > out2
    printf "      Average Frames:      %10.4f\n",avgFrames > out2
    printf "\n   Summary data for hbond lifetime analysis:\n\n" >> out3
    printf "   Summed Avg Lifetime:    %10.4f\n",avgLT >> out3
    printf "   Average Lifetime:       %10.4f\n",avgAvgLT >> out3
    printf "      Summed Frames:  %10.0f\n",totFrames >> out3
    printf "      Average Frames:      %10.4f\n",avgFrames >> out3

    if (denom>1) {
      sd_avgLT=sqrt(avgLTsq/(denom-1)); semAvgLT=(sd_avgLT/(sqrt(denom))); sd_totFrames=sqrt(avgFramessq/(denom-1)); semTotFrames=(sd_totFrames/(sqrt(denom)))
      printf "\n   SD lifetime:            %10.4f\n",sd_avgLT > out2
      printf "   SEM lifetime:           %10.4f\n",semAvgLT > out2
      printf "      SD Frames:           %10.4f\n",sd_totFrames > out2
      printf "      SEM Frames:          %10.4f\n\n",semTotFrames > out2
      printf "\n   SD lifetime:            %10.4f\n",sd_avgLT >> out3
      printf "   SEM lifetime:           %10.4f\n",semAvgLT >> out3
      printf "      SD Frames:           %10.4f\n",sd_totFrames > out3
      printf "      SEM Frames:          %10.4f\n\n",semTotFrames > out3
    } if (denom>1 && denom!=2) {print "----------------------------------------\n" >> out3 }
      if (denom==1) { print "   Single HBOND event, no SD or SEM calculation possible!" > out2;
             print "\n   Single HBOND event, no SD or SEM calculation possible!\n\n----------------------------------------\n" >> out3
           }
      if (denom==2) { print "\n   2 Hydrogen bond events found! No proper SD or SEM!" > out2;
             print "   2 Hydrogen bond events found! No proper SD or SEM!\n\n----------------------------------------\n" >> out3
           }
}
  close(out3)
  close(out2)
}

5列入力ファイルをインポートして2列を処理し、後で処理するために同じ列を別のファイルに入れます(out1)。その後、いくつかの統計を計算するためにファイルを処理する必要があります。しかし、これはVPSでは発生せず、私が得た値はすべて0.0000です。

問題はwhile関数にあるようです。

while ((getline<out1)>0) {
      avgLTsq+=(($1-avgAvgLT)^2)
      avgFramessq+=(($2-avgFrames)^2)
    }

スクリプトの最後に内容がファイルに出力されると、計算された合計と平均(、、、avgLT平均avgAvgLT)の合理的な値が得られるようです。統計セクション(、および)に達すると、すべての値は元の値ではなく0.0000ですが、両方の項目に印刷されます。totFramesavgFramessd_avgLTsemAvgLTsd_totFramessemTotFramesout2out3

out1「math」は、ファイルに対して個別にコマンドを実行できるようです。

awk ' BEGIN { avgAvgLT=1.4264 } { avgLTsq+=(($1-avgAvgLT)^2) } END { print avgLTsq }' analLT_multiple.out
awk ' BEGIN { avgFrames=4.4831 } { avgFramessq+=(($2-avgFrames)^2) } END { print avgFramessq }' analLT_multiple.out
awk ' BEGIN { avgLTsq=30.3478; denom=89 } { sd_avgLT=sqrt(avgLTsq/(denom-1)) } END { print sd_avgLT }' analLT_multiple.out
awk ' BEGIN { sd_avgLT=0.587249; denom=89 } {semAvgLT=(sd_avgLT/(sqrt(denom))) }  END { print semAvgLT }' analLT_multiple.out
awk ' BEGIN { avgFramessq=2040.22; denom=89 } { sd_totFrames=sqrt(avgFramessq/(denom-1)) } END { print sd_totFrames }' analLT_multiple.out
awk ' BEGIN { sd_totFrames=4.81501; denom=89 } { semTotFrames=(sd_totFrames/(sqrt(denom))) } END { print semTotFrames }' analLT_multiple.out

ゼロ以外の値を提供することで合理的に見えますが、スクリプトはすべての値を0.0000として提供します。また、複数のファイルを実行したときにスクリプトの変数値を印刷してみましたが、、、、およびすべて0または空の値を返しましdenomたが、変数はまだ機能していました。sd_avgLTsemAvgLTsd_totFramessemTotFrames

私の「結論」(ここで推測だと言いたい)は、前に述べたように、while関数に問題があるということです。何かはわかりませんが。

Pastebinにサンプル入力ファイルを入れました。https://pastebin.com/JsuTz0mD スクリプトを直接実行してみたい場合。

私のVPSシステムでこのスクリプトを動作させるための入力/フィードバックまたはソリューションを提供していただきありがとうございます。

答え1

ファイルに書き込むときにファイルに書き込まれるデータをフラッシュしない(GNUまたは)、書き込み用に開いたままにしておくawkファイルハンドルから何かを読み取っています。これは、このファイルのデータをチャンクで読み取ったときにデータが読み込まれないことを意味します。 BSDの実装にはこの問題はないようで、コードはOpenBSDやmacOSなどで期待どおりに動作します。awkmawkout1awkENDawk

回避策は簡単です。無条件ブロックでclose(out1)使用してください。END今後現在はそれをgetline閉じます。後ろにそれを読んでください。

>また、との一貫性を維持することをお勧めします>>。私はあなたが>このコードを完全に使用できると信じています。

答え2

@Kusalanandaはすでに何が間違っているかを言っているので、これは答えではありません。しかし、スクリプトを少し整理して読みやすくし、コードの重複を減らしましょう。

FNR == 1 {
    if ( NR != 1 ) {
        endfile()
    }
    avgLT = totFrames = denom = 0
    out1 = "analLT_" FILENAME
    out2 = "sumLT_" FILENAME
    out3 = "reportLT.txt"
    print "-> Input file is: " FILENAME > out3
    next
}

{
    avgLT += $4
    totFrames += $5
    ++denom
    printf "%10.4f %10.1f\n", $4, $5 > out1
}

END {
    endfile()
}

function endfile(       x, avgAvgLT, avgFrames, sd_avgLT,
                        semAvgLT, sd_totFrames, semTotFrames )
{
    if (avgLT == 0 && denom == 0 ) {
        x = "\nNO DATA POINTS IN INPUT => NO HYDROGEN BONDS DETECTED!"
        print x         > out1
        print x         > out2
        print x         > out3
    }
    else if (avgLT > 0) {
        avgAvgLT = avgLT / denom
        avgFrames = totFrames / denom

        close(out1)
        while ((getline < out1) > 0) {
            avgLTsq     += (($1 - avgAvgLT) ^ 2)
            avgFramessq += (($2 - avgFrames) ^ 2)
        }
        close(out1)

        printf "\n   Summary data for hbond lifetime analysis:\n\n"             > out2
        printf "   Summed Avg Lifetime:    %10.4f\n", avgLT                     > out2
        printf "   Average Lifetime:       %10.4f\n", avgAvgLT                  > out2
        printf "      Summed Frames:  %10.0f\n", totFrames                      > out2
        printf "      Average Frames:      %10.4f\n", avgFrames                 > out2

        printf "\n   Summary data for hbond lifetime analysis:\n\n"             > out3
        printf "   Summed Avg Lifetime:    %10.4f\n", avgLT                     > out3
        printf "   Average Lifetime:       %10.4f\n", avgAvgLT                  > out3
        printf "      Summed Frames:  %10.0f\n", totFrames                      > out3
        printf "      Average Frames:      %10.4f\n", avgFrames                 > out3

        if (denom == 1) {
            x = "   Single HBOND event, no SD or SEM calculation possible!"
            print x     > out2
            print ""    > out3
            print x     > out3
        }
        else if (denom > 1) {
            sd_avgLT = sqrt(avgLTsq / (denom - 1))
            semAvgLT = (sd_avgLT / (sqrt(denom)))
            sd_totFrames = sqrt(avgFramessq / (denom - 1))
            semTotFrames = (sd_totFrames / (sqrt(denom)))

            printf "\n   SD lifetime:            %10.4f\n", sd_avgLT            > out2
            printf "   SEM lifetime:           %10.4f\n", semAvgLT              > out2
            printf "      SD Frames:           %10.4f\n", sd_totFrames          > out2
            printf "      SEM Frames:          %10.4f\n\n", semTotFrames        > out2

            printf "\n   SD lifetime:            %10.4f\n", sd_avgLT            > out3
            printf "   SEM lifetime:           %10.4f\n", semAvgLT              > out3
            printf "      SD Frames:           %10.4f\n", sd_totFrames          > out3
            printf "      SEM Frames:          %10.4f\n\n", semTotFrames        > out3

            if (denom == 2) {
                x = "   2 Hydrogen bond events found! No proper SD or SEM!"
                print ""        > out2
                print x         > out2
                print x         > out3
        }
    }

    print "\n\n----------------------------------------\n"                      > out3

    close(out1)
    close(out2)
    close(out3)
}

out1のwhile getlineループは、スクリプト本体にout1を書くのではなく、配列にデータを格納できるので、実際には必要ありません。たとえば、次のようになります。

FNR == 1 {
    if ( NR != 1 ) {
        endfile()
    }
    avgLT = totFrames =  denom = 0
    out1 = "analLT_" FILENAME
    out2 = "sumLT_" FILENAME
    out3 = "reportLT.txt"
    print "-> Input file is: " FILENAME > out3
    next
}

{
    avgLT += $4
    totFrames += $5
    ++denom
    fnr2avgLT[FNR] = avgLT
    fnr2totFrames[FNR] = totFrames
}

END {
    endfile()
}

function endfile(       i, x, avgAvgLT, avgFrames, sd_avgLT,
                        semAvgLT, sd_totFrames, semTotFrames )
{
    if (avgLT == 0 && denom == 0 ) {
        x = "\nNO DATA POINTS IN INPUT => NO HYDROGEN BONDS DETECTED!"
        print x         > out1
        print x         > out2
        print x         > out3
    }
    else if (avgLT > 0) {
        avgAvgLT = avgLT / denom
        avgFrames = totFrames / denom

        for (i=1; i<=FNR; i++) {
            avgLT = fnr2avgLT[i]
            totFrames = fnr2totFrames[i]
            printf "%10.4f %10.1f\n", avgLT, totFrames > out1

            avgLTsq     += ((avgLT - avgAvgLT) ^ 2)
            avgFramessq += ((totFrames - avgFrames) ^ 2)
        }

        printf "\n   Summary data for hbond lifetime analysis:\n\n"             > out2
        printf "   Summed Avg Lifetime:    %10.4f\n", avgLT                     > out2
        printf "   Average Lifetime:       %10.4f\n", avgAvgLT                  > out2
        printf "      Summed Frames:  %10.0f\n", totFrames                      > out2
        printf "      Average Frames:      %10.4f\n", avgFrames                 > out2

        printf "\n   Summary data for hbond lifetime analysis:\n\n"             > out3
        printf "   Summed Avg Lifetime:    %10.4f\n", avgLT                     > out3
        printf "   Average Lifetime:       %10.4f\n", avgAvgLT                  > out3
        printf "      Summed Frames:  %10.0f\n", totFrames                      > out3
        printf "      Average Frames:      %10.4f\n", avgFrames                 > out3

        if (denom == 1) {
            x = "   Single HBOND event, no SD or SEM calculation possible!"
            print x     > out2
            print ""    > out3
            print x     > out3
        }
        else if (denom > 1) {
            sd_avgLT = sqrt(avgLTsq / (denom - 1))
            semAvgLT = (sd_avgLT / (sqrt(denom)))
            sd_totFrames = sqrt(avgFramessq / (denom - 1))
            semTotFrames = (sd_totFrames / (sqrt(denom)))

            printf "\n   SD lifetime:            %10.4f\n", sd_avgLT            > out2
            printf "   SEM lifetime:           %10.4f\n", semAvgLT              > out2
            printf "      SD Frames:           %10.4f\n", sd_totFrames          > out2
            printf "      SEM Frames:          %10.4f\n\n", semTotFrames        > out2

            printf "\n   SD lifetime:            %10.4f\n", sd_avgLT            > out3
            printf "   SEM lifetime:           %10.4f\n", semAvgLT              > out3
            printf "      SD Frames:           %10.4f\n", sd_totFrames          > out3
            printf "      SEM Frames:          %10.4f\n\n", semTotFrames        > out3

            if (denom == 2) {
                x = "   2 Hydrogen bond events found! No proper SD or SEM!"
                print ""        > out2
                print x         > out2
                print x         > out3
        }
    }

    print "\n\n----------------------------------------\n"                      > out3

    close(out1)
    close(out2)
    close(out3)
}

もちろん、テストするサンプル入力/出力を提供していないので、上記の項目はすべてテストされていませんが、すべてのバグを簡単に見つけて修正できることを願っています。

関連情報