AWK를 사용하여 한 CSV 파일에서 다른 CSV 파일로 특정 열을 추출하는 방법은 무엇입니까?

AWK를 사용하여 한 CSV 파일에서 다른 CSV 파일로 특정 열을 추출하는 방법은 무엇입니까?

다음과 같은 필드가 포함된 매우 큰 CSV 로그 파일이 있습니다.

aaa=somedata1,bbb=somedata2,ccc=somedata3,eee=somedata5,hhh=somedata8
aaa=somedata1,ddd=somedata4,fff=somedata6,hhh=somedata8
aaa=somedata1,bbb=somedata2,hhh=somedata8,ggg=somedata9,jjj=somedata11

이 파일의 문제는 값이 없을 때 생성 장치에 "fieldname="이 포함되어 있지 않기 때문에 필드 누락으로 인해 CSV가 정렬되지 않은 것처럼 보인다는 것입니다(따라서 필드가 누락될 때마다 나머지는 제거됩니다). 현재 필드가 CSV의 왼쪽으로 드래그됩니다.

내 생각은 AWK를 사용하여 특정 관련 열만 추출하고 이를 새 CSV로 출력해야 한다는 것입니다.

예를 들어, 위의 예에서 "aaa" 및 "hhh" 필드가 포함된 모든 열을 추출하여 새 CSV가 다음과 같이 보이도록 하려고 합니다.

aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8

그러나 두 가지 질문이 있습니다.

  1. AWK에서 여러 조건을 찾는 방법을 모르겠습니다. 필수 필드/키워드의 이름을 TXT 파일에 쓰고 AWK에서 읽어보려고 시도했지만 할 수 없었습니다.
  2. 결과 열을 인쇄하려고 할 때마다 새 CSV는 하나의 큰 열만 인쇄하며 열을 분리하여 인쇄하는 방법을 찾을 수 없는 것 같습니다.

어떤 도움을 주셔서 감사합니다!

---편집 1---

예, 다음과 같은 별도의 AWK 명령을 사용해 보았습니다.

awk '{for (i=1;i<=NF;i++) if ($i ~ /aaa/) { print $i}}' > aaa.csv
awk '{for (i=1;i<=NF;i++) if ($i ~ /hhh/) { print $i}}' > hhh.csv

그런 다음 다음을 사용해 보십시오(물론 추출하려는 열이 총 10개 있지만 간략하게 설명하기 위해 예제에는 2개만 넣었습니다).

paste -d "," aaa.csv hhh.csv > Allcolumns.csv

---편집 2---

총 10개의 관련 열이 있고 이를 새 파일로 추출하고 싶습니다. 원본 파일은 로그이므로 모든 행에 나타나는 열이 실제로 필요한 열인지 확인합니다. 만약 원본 파일에 나타나지 않는다면, 가장 좋은 방법은 최종 파일에 "aaa,hhh,,iii"과 같은 내용을 반영하는 것입니다.

답변1

tag2val[]데이터에 태그=값 쌍이 있을 때마다 먼저 맵을 보관할 배열을 생성한 다음(아래) 태그(이름 또는 키라고도 함)별로 모든 값을 참조할 수 있는 것이 가장 좋습니다 .

모든 Unix 시스템의 모든 쉘에서 awk를 사용하십시오.

$ cat tst.awk
BEGIN {
    FS = OFS = ","
    numTags = split("aaa,hhh",tags)
}
{
    delete tag2val
    for (i=1; i<=NF; i++) {
        tag = $i
        sub(/=.*/,"",tag)
        tag2val[tag] = $i
    }

    for (i=1; i<=numTags; i++) {
        tag = tags[i]
        printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
    }
}

$ awk -f tst.awk file
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8

각 줄에서 가능한 모든 필드를 인쇄하려는 경우 첫 번째 패스에서 각 줄의 가능한 모든 필드를 식별하는 2단계 접근 방식입니다.

$ cat tst.awk
BEGIN {
    FS = OFS = ","
}
NR==FNR {
    for (i=1; i<=NF; i++) {
        tag = $i
        sub(/=.*/,"",tag)
        if ( !seen[tag]++ ) {
            tags[++numTags] = tag
        }
    }
    next
}
{
    delete tag2val
    for (i=1; i<=NF; i++) {
        tag = $i
        sub(/=.*/,"",tag)
        tag2val[tag] = $i
    }

    for (i=1; i<=numTags; i++) {
        tag = tags[i]
        printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
    }
}

$ awk -f tst.awk file file
aaa=somedata1,bbb=somedata2,ccc=somedata3,eee=somedata5,hhh=somedata8,,,,
aaa=somedata1,,,,hhh=somedata8,ddd=somedata4,fff=somedata6,,
aaa=somedata1,bbb=somedata2,,,hhh=somedata8,,,ggg=somedata9,jjj=somedata11

모든 행에 나타나는 필드만 인쇄하려는 경우:

$ cat tst.awk
BEGIN {
    FS = OFS = ","
}
NR==FNR {
    for (i=1; i<=NF; i++) {
        tag = $i
        sub(/=.*/,"",tag)
        cnt[tag]++
    }
    next
}
FNR==1 {
    for (tag in cnt) {
        if ( cnt[tag] == (NR-1) ) {
            tags[++numTags] = tag
        }
    }
}
{
    delete tag2val
    for (i=1; i<=NF; i++) {
        tag = $i
        sub(/=.*/,"",tag)
        tag2val[tag] = $i
    }

    for (i=1; i<=numTags; i++) {
        tag = tags[i]
        printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
    }
}

$ awk -f tst.awk file file
hhh=somedata8,aaa=somedata1
hhh=somedata8,aaa=somedata1
hhh=somedata8,aaa=somedata1

필드 출력의 순서가 중요한 경우 이는 간단한 조정이기도 합니다. 예를 들어 입력 순서를 유지하려면 다음과 같이 첫 번째 블록에 배열을 만들어 증분 카운트를 각 새 레이블에 매핑하면 됩니다.

$ cat tst.awk
BEGIN {
    FS = OFS = ","
}
NR==FNR {
    for (i=1; i<=NF; i++) {
        tag = $i
        sub(/=.*/,"",tag)
        if ( !cnt[tag]++ ) {
            order[++totTags] = tag
        }
    }
    next
}
FNR==1 {
    for (i=1; i<=totTags; i++) {
        tag = order[i]
        if ( cnt[tag] == (NR-1) ) {
            tags[++numTags] = tag
        }
    }
}
{
    delete tag2val
    for (i=1; i<=NF; i++) {
        tag = $i
        sub(/=.*/,"",tag)
        tag2val[tag] = $i
    }

    for (i=1; i<=numTags; i++) {
        tag = tags[i]
        printf "%s%s", tag2val[tag], (i<numTags ? OFS : ORS)
    }
}

$ awk -f tst.awk file file
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8

답변2

사용할 수 있는 옵션이 있는 경우밀러, 그러면 데이터가 완전히 Miller(키-값 쌍) 형식으로 되어 있으며 필드 이름을 직접 누를 dkvp수 있습니다 .cut

$ mlr --dkvp cut -f aaa,hhh file.csv
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8

또는 다음 명령을 사용하여 누락된 필드를 복원할 수 있습니다 unsparsify.

$ mlr --dkvp unsparsify file.csv
aaa=somedata1,bbb=somedata2,ccc=somedata3,eee=somedata5,hhh=somedata8,ddd=,fff=,ggg=,jjj=
aaa=somedata1,bbb=,ccc=,eee=,hhh=somedata8,ddd=somedata4,fff=somedata6,ggg=,jjj=
aaa=somedata1,bbb=somedata2,ccc=,eee=,hhh=somedata8,ddd=,fff=,ggg=somedata9,jjj=somedata11

답변3

awk -F "," '{for(i=1;i<=NF;i++){if($i ~ /aaa|hhh/){print $i}}}' filename|sed "N;s/\n/,/g"

산출

aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8
aaa=somedata1,hhh=somedata8

관련 정보