첫 번째 열로 파일 분할: 열려 있는 파일이 너무 많습니다.

첫 번째 열로 파일 분할: 열려 있는 파일이 너무 많습니다.

이것은 질문의 확장입니다.첫 번째 열 값을 기준으로 파일을 여러 파일로 분할. 방금 가입했기 때문에 위 질문에 의견을 추가할 만큼 담당자 포인트가 부족합니다. 그래서 반복해서 사과드립니다.

다음 명령을 사용하여 파일을 첫 번째 열로 분할했습니다.

awk -F"\t" '{print>"subfolder/"$1}' inputfile

그러나 나는 하나를 얻었습니다 awk: cannot open for output (Too many open files).

그런 다음 명령을 다음으로 변경했습니다.

awk -F"\t" '{print>"subfolder/"$1}{close("subfolder/"$1)}' inputfile.

그러나 파일을 닫으면 0바이트 출력 파일이 생성됩니다.

답변1

print >filenamein을 사용하면 awk파일이 열리고 파일이 있는 경우 길이가 0으로 잘립니다. awk그러면 그럴 것이다파일을 열어두세요프로그램이 끝날 때까지. 많은 파일에 대해 이 작업을 수행하면 알다시피 리소스 제한이 발생하게 됩니다.

당신이 해야 할 일은 close(filename)당신의 몫 입니다 close("subfolder/"$1). $1올바른 값을 유지하면서 이 작업을 수행 해야 합니다 .

그러나 이는 다음을 의미합니다.다음 print >파일을 열고 이전 내용을 자릅니다.

이 문제를 해결하려면 print >>대신 를 사용하십시오 print >. 그러면 파일이 열립니다.추가.

다음 문제는 awk프로그램을 두 번째로 실행하면 첫 번째 실행 결과가 추가된다는 점이다. 이는 프로그램을 다시 실행하기 전에 삭제하거나 이름을 바꿀 출력 파일을 구성해야 함을 의미합니다.

전체 스크립트는 다음과 같습니다.

#!/bin/sh

rm -rf subfolder   # remove old output files 
mkdir subfolder    # and recreate output directory

awk -F '\t' '{ fname = "subfolder/" $1; print >>fname; close(fname) }' inputfile

데이터가 첫 번째 열에서 정렬된 경우 실제로 다음을 수행해야 할 때까지 파일을 닫지 않는 매우 작은 최적화의 이점을 누릴 수 있습니다.

awk -F '\t' '
    fname != "subfolder/" $1 {
        if (fname != "")
            close(fname)
        fname = "subfolder/" $1
    }
    { print >>fname }' inputfile

입력이 첫 번째 필드에서 정렬되는 경우 위와 print >>같이 변경할 수 있습니다 . print >데이터가 정렬되지 않은 경우에도 을 사용하면 print >>그 사이에 출력 파일을 닫았다가 다시 열 필요 없이(느릴 수 있음) 동일한 첫 번째 필드가 있는 여러 개의 연속 행을 동일한 파일에 기록합니다.


Mosvy가 의견에서 지적했듯이, 파일 이름에 다음 값을 사용하고 싶은 유혹을 느낄 수 있습니다.합리적인맹목적으로 쓰기 전에.

값에 소문자 또는 대문자 영숫자 문자(및 밑줄)만 포함되어 있는지 명시적으로 확인하여 이를 수행할 수 있습니다.

awk -F '\t' '
    fname != "subfolder/" $1 {
        if (fname != "")
            close(fname)
        fname = "subfolder/" $1

        if (fname ~ /[^a-zA-Z0-9_]/) {
            print "Bad filename: " fname >"/dev/stderr"
            exit(1)
        }
    }
    { print >>fname }' inputfile

그는 또한 출력 파일에 대한 리디렉션을 처리하는 대체 방법을 제안했는데, 이는 파일이 처음 열릴 때 파일을 자르고 나중에 추가하기 위해 파일을 여는 것입니다. 그는 파일 이름을 연관 해시의 키로 저장하여 이를 수행합니다.

    {
        if (names[fname]++)
            print >>fname
         else
            print >fname
    }

관련 정보