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이 아닌 값을 제공하여 합리적으로 보이지만 스크립트는 모든 값을 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)
}

물론 테스트할 샘플 입력/출력을 제공하지 않았기 때문에 위의 모든 항목은 테스트되지 않았지만 모든 버그를 쉽게 발견하고 수정할 수 있기를 바랍니다.

관련 정보