AWK
파일에 일련의 변수가 누적되도록 대용량 파일의 큰 하위 집합을 처리하려면 (*)를 사용해야 합니다 .
AWK
파일 와일드카드를 사용하여 여러 파일 이름을 전달하는 간단한 방법은 작은 파일 세트에 적합하지만 "Argument list too long"
프로덕션 규모의 파일 세트로 실행할 때 예상한 결과를 얻습니다.
이러한 유형의 문제를 해결하기 위한 모범 사례는 무엇입니까?
일부 세부정보:
전체 세트는 20-50K 파일입니다. 현재 단일 실행의 하위 세트는 5-10K입니다(그러나 쉽게 확장할 수 있다면 좋을 것입니다).
파일 세트에서 각 단어의 발생 횟수를 세어 각 파일에 런타임 정의 가중치를 부여해야 합니다. 동일한 파일의 각 단어는 동일한 가중치를 가지지만, 다른 파일에 나타나는 동일한 단어는 다른 가중치를 갖습니다. 그런 다음 각 단어에 대한 문서 무게를 추가합니다.
따라서 파일 세트를 더 작은 하위 세트로 분할한다는 것은 중간 결과를 집계하는 것을 의미합니다. 매우 우아해 보이지 않으며 여러 중간 파일을 결합할 때 부동 소수점을 추가해야 하므로 전체 프로세스의 가독성과 직관성이 떨어집니다.
내가 생각할 수 있는 또 다른 방법은
awk
&의 출력을 제공하는 것입니다. 내가 싫어하는 점은 /의 가독성을 희생하고 파일별 가중치, 카운터 및 배열을 재설정하기 위해 파일 간의 특정 구분 기호를 구문 분석하는 작업을 수행하는 것입니다.find
cat
BEGINFILE
ENDFILE
현재 폴더에서 처리할 파일의 하위 집합은 별도의 파일로 제공됩니다. 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
.
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 통계는 여기에 있습니다..