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을 통해 두 개의 인수만 허용하거나 파일에서 읽을 수 있지만 일반적으로 매우 빠르게 실행됩니다. 실제 실행자는 타사 애플리케이션/바이너리이며 작동 방식에 대한 세부 정보를 모릅니다.

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 호출이 발생한다는 의미입니다.

런타임을 어떻게 개선할 수 있나요?

추출된 모든 필드를 하나의 명령으로 연결하는 것과 같이 스크립트를 한 번 실행하도록 하는 방법을 고려했습니다.

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각 입력 라인은 정확히 한 라인의 출력을 생성합니다. 내 솔루션은 외부 프로그램의 동작에 따라 달라집니다.
  • paste입력 파일을 의 출력과 한 줄씩 결합합니다(사용) 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위의 줄을 읽으십시오. 각 파일에는 입력 파일의 한 줄과 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첫 번째 열과 두 번째 열 사이의 공백이 포함되며 RY값은하다아니요두 번째 열 값의 마지막 문자를 포함합니다(즉, 두 번째 점 뒤의 숫자). 이건 정말 말이 안 되거든요 왜냐하면

        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

즉, 에 보내는 문자열의 두 번째 점 뒤에 숫자를 포함시킵니다 rev.

그리고, 두 개의 겹치지 않지만 연속된 하위 문자열을 추출한 다음 $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.

귀하의 질문에 있는 데이터가 타당하고 내부적으로 일관성이 있도록 노력하십시오.


즉, 합리적인 답변을 얻기 위해 정확한 질문의 모든 세부 사항을 정확하게 게시하는 것이 항상 필요한 것은 아니라는 점을 이해하신 것 같습니다. 이러한 정신으로 질문의 무결성을 손상시키지 않으면서 질문을 더 쉽게 이해할 수 있도록 노력하십시오. 귀하의 데이터가 눈을 아프게 합니다.

  • 각 줄의 처음 세 문자는 "K13"입니다. 이로 인해 다양한 캐릭터를 보기가 더 어려워집니다.
  • 5개 행 중 3개 행에서 처음 5개 문자(즉, 첫 번째 열 값 전체)는 "K1353"입니다.
  • 두 번째 열의 값은 18자 길이의 문자, 숫자, 점이 의미 없이 뒤섞여 있어 읽고 이해하기 어렵습니다.
  • 두 번째 열의 값을 확인하세요.
    • 다섯 가지 요소 중 네 가지가 "S"로 시작합니다.
    • "SF"로 시작하는 세 줄입니다.
    • 세 줄에서 세 번째 문자는 "3"입니다.
    • 네 줄 중 10번째 문자는 "D"입니다.
    • 세 줄 중 9번째와 10번째 문자는 "KD"입니다.
    • 4줄에서 11번째와 12번째 문자는 "83", 16번째 문자는 "1"이다.
    • 세 줄에서 문자 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"와는 거의 "단어 검색" 퍼즐 중 하나와 비슷합니다. ("KD832231"이 두 번 나타나므로 "132238DK"만 추적 가능한 것은 아닙니다.)

</rant>

관련 정보