CSV 데이터를 여러 개의 개별 파일로 필터링

CSV 데이터를 여러 개의 개별 파일로 필터링

다음과 같은 CSV 파일이 있습니다 file1.csv.

something;AD;sss;Andorra;nothing;type_1;sss
something222;AD;sss222;Andorra;nothing222;type_2;aaa
thing;NL;thing3;Netherlands;thing;type_2;bb
etc;US;etc;United States;etc;type_2;nothing

국가별로 별도의 파일을 만들고 싶습니다. 나는 다음과 같이 grep을 만듭니다.

grep -e "\;AD\;.*\;Andorra\;" file1.csv > fileAD.csv
grep -e "\;NL\;.*\;Netherlands\;" file1.csv > fileNL.csv
grep -e "\;US\;.*\;United\sStates\;" file1.csv > fileUS.csv

이것은 효과가 있지만 전 세계의 모든 국가가 있으므로 각 국가에 대해 이 줄을 쓰고 싶지 않습니다. 다른 해결책이 있나요?

type_1또한 및 이 포함된 열이 있습니다 type_2. 이 점을 고려해야 합니다. 국가별 파일을 모두 만든 후에는 국가별로 새 파일을 만들어서 type_1사용해야 합니다 type_2.

예를 들어 안도라의 경우 다음 파일이 필요합니다.

  • fileAD.csv:

    something;AD;sss;Andorra;nothing;type_1;sss
    something222;AD;sss222;Andorra;nothing222;type_2;aaa
    
  • fileADtype_1.csv:

    something;AD;sss;Andorra;nothing;type_1;sss
    
  • fileADtype_2.csv:

    something222;AD;sss222;Andorra;nothing222;type_2;aaa
    

약어가 있는 열만 찾는 것이 괜찮다고 생각하지만 보안상의 이유로 두 개의 열을 원합니다. 하나는 AD전체 이름이고 다른 하나는 전체 이름입니다.Andorra

답변1

데이터가 다음과 같다고 가정합니다.단순한CSV 데이터, 즉 필드에 구분 기호나 줄 바꿈이 포함되어 있지 않습니다.

awk -F ';' '
    {
        print > "file" $2    ".csv"
        print > "file" $2 $6 ".csv"
    }' file1.csv

이렇게 하면 각 행이 두 번 인쇄됩니다. 한 번은 두 번째 필드 값으로만 ​​지정된 파일에, 한 번은 두 번째와 여섯 번째 필드 값의 조합으로 지정된 파일에 인쇄됩니다. 질문의 텍스트에 따르면 각 출력 파일 이름에는 문자열 접두사가 붙고 file접미사가 붙습니다..csv

파일 이름에 사용된 두 필드의 값은 검증되지 않습니다.

네 번째 필드에 국가 이름을 병합하려면:

awk -F ';' '
    {
        print > "file_" $2 "-" $4        ".csv"
        print > "file_" $2 "-" $4 "_" $6 ".csv"
    }' file1.csv

주어진 데이터에 대해 다음 파일이 생성됩니다.

file_AD-Andorra.csv
file_AD-Andorra_type_1.csv
file_AD-Andorra_type_2.csv
file_NL-Netherlands.csv
file_NL-Netherlands_type_2.csv
file_US-United States.csv
file_US-United States_type_2.csv

위의 코드는 GNU를 사용하는 시스템에서 잘 작동합니다 awk. 다른 awk구현에서는 동시에 쓰기 위해 너무 많은 파일을 열어 놓으면 문제가 발생할 수 있습니다. 이러한 awk구현에서는 더 똑똑해야 하며 파일에 쓴 후에는 파일을 닫는 것을 기억해야 합니다. 파일이 닫혀지면 >>다음에 데이터가 파일에 기록될 때 인쇄해야 합니다. 그렇지 않으면 파일이 잘립니다.

awk -F ';' '
    function do_print(name) {
        if (seen[name] == 1) print >>name  # append to file
        else                 print  >name  # first write, truncate file
        close(name)
        seen[name] = 1
    }
    {
        do_print("file_" $2 "-" $4        ".csv")
        do_print("file_" $2 "-" $4 "_" $6 ".csv")
    }' file1.csv

awk그러면 표현식을 사용할 수 없는 OpenBSD에서도 코드가 실행됩니다 print >.


추가 (재미를 위해): awk코드에서 일부 통계를 출력하도록 합니다.

awk -F ';' '
    function do_print(name) {
        if (seen[name] > 0) print >>name  # append to file
        else                print  >name  # first write, truncate file
        close(name)
        seen[name]++
    }
    {
        do_print("file_" $2 "-" $4        ".csv")
        do_print("file_" $2 "-" $4 "_" $6 ".csv")
    }
    END {
        for (name in seen)
            printf "Wrote %d lines to \"%s\"\n", seen[name], name >"/dev/stderr"
    }' file1.csv

처리가 끝나면 오류 스트림에 일부 통계가 기록됩니다. 주어진 데이터에 대해:

Wrote 1 lines to "file_NL-Netherlands.csv"
Wrote 1 lines to "file_US-United States_type_2.csv"
Wrote 1 lines to "file_AD-Andorra_type_1.csv"
Wrote 2 lines to "file_AD-Andorra.csv"
Wrote 1 lines to "file_NL-Netherlands_type_2.csv"
Wrote 1 lines to "file_US-United States.csv"
Wrote 1 lines to "file_AD-Andorra_type_2.csv"

관련 정보