단일 프로세스를 사용하면 AWK 프로세스가 하나의 거대한 파일 세트가 됩니다.

단일 프로세스를 사용하면 AWK 프로세스가 하나의 거대한 파일 세트가 됩니다.

AWK파일에 일련의 변수가 누적되도록 대용량 파일의 큰 하위 집합을 처리하려면 (*)를 사용해야 합니다 .

AWK파일 와일드카드를 사용하여 여러 파일 이름을 전달하는 간단한 방법은 작은 파일 세트에 적합하지만 "Argument list too long"프로덕션 규모의 파일 세트로 실행할 때 예상한 결과를 얻습니다.

이러한 유형의 문제를 해결하기 위한 모범 사례는 무엇입니까?


일부 세부정보:

  • 전체 세트는 20-50K 파일입니다. 현재 단일 실행의 하위 세트는 5-10K입니다(그러나 쉽게 확장할 수 있다면 좋을 것입니다).

  • 파일 세트에서 각 단어의 발생 횟수를 세어 각 파일에 런타임 정의 가중치를 부여해야 합니다. 동일한 파일의 각 단어는 동일한 가중치를 가지지만, 다른 파일에 나타나는 동일한 단어는 다른 가중치를 갖습니다. 그런 다음 각 단어에 대한 문서 무게를 추가합니다.

  • 따라서 파일 세트를 더 작은 하위 세트로 분할한다는 것은 중간 결과를 집계하는 것을 의미합니다. 매우 우아해 보이지 않으며 여러 중간 파일을 결합할 때 부동 소수점을 추가해야 하므로 전체 프로세스의 가독성과 직관성이 떨어집니다.

  • 내가 생각할 수 있는 또 다른 방법은 awk&의 출력을 제공하는 것입니다. 내가 싫어하는 점은 /의 가독성을 희생하고 파일별 가중치, 카운터 및 배열을 재설정하기 위해 파일 간의 특정 구분 기호를 구문 분석하는 작업을 수행하는 것입니다.findcatBEGINFILEENDFILE

  • 현재 폴더에서 처리할 파일의 하위 집합은 별도의 파일로 제공됩니다. A. BEGINFILE필요하지 않은 파일은 내 섹션에서 건너뜁니다.

  • 각 문서의 무게
  • 파일 간 집계 수단에서 파일 가중치 계산 분리읽기가 수십 GB를 초과합니다. 이를 방지하고 싶습니다.

(*) 아니면 AWK이런 종류의 처리에 가장 적합한 도구가 아닐 수도 있습니다. 그렇다면 어떤 대안을 추천하시겠습니까?

답변1

매개변수가 너무 많으면 파일을 직접 열고 처리해야 합니다. awk를 사용하면 확장을 사용하지 않고도 다음을 사용할 수 있습니다(Jeff의 답변과 동일한 아이디어).

awk '{ filename = $0; while(getline < filename > 0) { print $0; }}'

예를 들어 find다음 명령을 결합하여 필요한 파일을 찾습니다.

find /etc/ -maxdepth 1 -type f -perm -444 -size 1 | \
  awk '{ filename = $0; while(getline < filename > 0) { print filename ":" $0; }}'

또한 awk 버전에 따라 처리를 위해 더 많은 파일을 푸시할 수 있습니다.여기에 문서화된 대로.

프로그램은 ARGC 및 ARGV의 요소를 변경할 수 있습니다. awk가 입력 파일의 끝에 도달할 때마다 ARGV의 다음 요소를 다음 입력 파일의 이름으로 사용합니다. 프로그램은 다른 문자열을 저장하여 읽는 파일을 변경할 수 있습니다. 표준 입력을 나타내려면 "-"를 사용하십시오. 추가 요소를 저장하고 ARGC를 증가시키면 추가 파일을 읽을 수 있습니다.

예를 사용하여 설명하십시오.

find /etc/ -maxdepth 1 -type f -perm -444 -size 1 | \
  awk '
    # When reading from STDIN, assume it is a list of files to read
    FILENAME == "-" { ARGV[ARGC] = $0; ARGC += 1 }
    # When not reading STDIN, it is a file to process
    FILENAME != "-" { print "---", FILENAME ":" FNR ":" $0; }
    # These will run after every file, including STDIN, hence the check
    BEGINFILE { if (FILENAME != "-") { print ">>>", FILENAME; } }
    ENDFILE   { if (FILENAME != "-") { print "<<<", FILENAME, FNR, "lines"; } }'

답변2

파일 이름에 따옴표나 공백이 포함되어 있지 않으면 한 가지 옵션은 함께 쌓는 것입니다 cat.

printf '%s ' * | xargs cat | awk ...

printf위의 코드는 내장()을 사용하여 각 파일 이름을 보내기 전에 인쇄하여 "인수 목록이 너무 김" 오류를 해결합니다. 그러면 xargs파일 이름을 일괄 처리로 분할하고 에 보낸 cat다음 출력을 에 보냅니다 awk.

그러나 xargs를 사용하지 마십시오

GNU awk(gawk)를 사용할 수 있는 경우4.1 이상, 디렉터리 자체를 읽을 수 있는 확장이 포함된 동적 모듈 로딩을 도입하여 문제를 우회합니다.

다음은 전달한 디렉터리의 파일을 열고 읽는 샘플 gawk 프로그램입니다. 그런 다음 관심 있는 각 파일을 명시적으로 읽어야 합니다. 이것의 장점은 각 파일을 읽을 수 있는 (GNU) awk 프로그램이 있다는 것입니다.

@load "readdir"
@load "filefuncs"

BEGIN { FS = "/" }
{
        result = stat($2, statdata)
        if (statdata["type"] != "file")
                next
        FS = " "
        while(getline < statdata["name"] > 0) {
                #print $1
        }
        FS = "/"
}

스크립트의 메인 루프는 명령줄에 제공된 각 인수를 반복하고 이를 디렉터리로 열려고 시도합니다. 결과 필드는 다음과 같습니다.

  • $1 = 아이노드 번호
  • $2 = 파일 이름
  • $3 = 파일 형식

그런 다음 filefuncs 함수를 사용하여 stat파일 유형을 확인합니다. 일반 파일이 아니면 건너뛰겠습니다. 그렇지 않으면 이를 FS다시 정상으로 설정 하고 이를 사용하여 getline파일을 읽습니다. 각 파일이 처리된 후 FS /에서 시작할 수 있도록 FS를 다시 재설정합니다 readdir.

나는 배웠다gawk의 readdir은 여기에 있습니다그리고 약gawk의 filefuncs 통계는 여기에 있습니다..

관련 정보