정렬하지 않고 특정 열을 기반으로 텍스트 파일에서 고유한 데이터를 필터링합니다.

정렬하지 않고 특정 열을 기반으로 텍스트 파일에서 고유한 데이터를 필터링합니다.

다음 형식의 10-100k 줄의 다양한 텍스트 파일이 있습니다.

"2018-12-07 23:21:32",XX,99,ZZZ,250,REMOVED
"2018-12-07 23:25:17",XX,99,ZZZ,250,AVAILBLE
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

위의 예에서는 열 2, 3, 4가 동일한 3개의 레코드(XX,99,ZZZ - 행 1/2/6)가 있음을 알 수 있습니다. 처음 두 행을 삭제하고 마지막 행만 유지해야 합니다.

원하는 출력은 아래와 같습니다.

"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

매우 느리고 100k~라인의 파일에 대해 메모리 오류를 발생시키는 PHP 스크립트가 있습니다.

답변1

마지막 항목만 남기고 모두 삭제하는 것보다 일련의 중복 항목 중 첫 번째 항목만 남기고 모두 삭제하는 것이 더 쉽습니다. 다음과 같이 시도해 볼 수 있습니다.

$ tac file | awk -F, '!seen[$2 FS $3 FS $4]++' | tac
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

답변2

BEGIN { FS = "," }

FNR == NR {
    if (seen[$2,$3,$4])
        delete lines[seen[$2,$3,$4]]

    lines[FNR]
    seen[$2,$3,$4] = FNR

    next
}

FNR in lines

프로그램은 awk동일한 파일을 두 번 읽을 것으로 예상합니다. 파일을 처음 읽을 때 FNR == NR블록만 실행됩니다. lines배열의 키로 출력할 줄 번호를 기억합니다 . 두 번째, 세 번째, 네 번째 열의 특정 조합이 있는 행이 이미 표시된 경우 가장 가까운 행 번호를 키로 삽입하고 이전(문 delete.

파일의 두 번째 구문 분석 중에 발생하는 모든 일은 배열에서 현재 줄 번호를 조회하는 것입니다 lines. 발견되면 해당 행을 인쇄하십시오.

동일한 코드의 "한 줄" 버전을 실행하는 예:

$ awk -F, 'FNR==NR { if(s[$2,$3,$4]) delete l[s[$2,$3,$4]]; l[FNR]; s[$2,$3,$4]=FNR; next}; FNR in l' file file
"2018-12-07 23:29:05",DD,11,AAA,250,REMOVED
"2018-12-07 23:30:00",CH,00,UUU,250,REMOVED
"2018-12-07 23:31:45",MM,33,OOO,250,REMOVED
"2018-12-07 23:46:41",XX,99,ZZZ,250,REMOVED

관련 정보