sed, awk 또는 tr을 사용하고 콜론(:)을 구분 기호로 사용하여 각 줄을 CSV 형식으로 분할합니다.

sed, awk 또는 tr을 사용하고 콜론(:)을 구분 기호로 사용하여 각 줄을 CSV 형식으로 분할합니다.

현재 다음과 같이 하나의 열로 정렬된 거대한 고객 계정 정보 파일이 있습니다. :각 행을 분할하는 구분 기호로 사용하고 싶습니다 . 그런데 이렇게 할 때 각 행에 대해 분리할 때 새 열을 만들고 각 행 뒤의 데이터를 :해당 열에 넣고 싶습니다 . 나의 궁극적인 목표는 이를 CSV 형식으로 변환하여 데이터 분석 및/또는 데이터베이스 구축을 위해 어딘가로 가져올 수 있도록 하는 것입니다.

firstName:John
middleName:null
lastName:Doe
companyName:John Doe Corp
suffix:null
primaryEmail:[email protected]
primaryPhone:555.555.5555
secondaryEmail:[email protected]
secondaryPhone:null

또한 이는 고객당 총 행 수가 아닙니다. 고객당 55개의 행이 있습니다.

답변1

perl모든 데스크탑 또는 서버 Linux 배포판에서 사용 가능한 것을 사용하십시오 .

perl -lne '
   BEGIN{$,=","}
   ($k,$v)=split":",$_,2;
   next unless defined $v;
   for($k,$v){s/"/""/g,$_=qq{"$_"}if/[$,"]/}
   $k=$t{$k}//=$t++;
   if(exists$f[$k]){print@f;@f=()}
   $f[$k]=$v;
   END{print@f;print STDERR sort{$t{$a}<=>$t{$b}}keys%t}
' your_file

전체 파일을 처리한 후 헤더(필드 이름을 포함하는 첫 번째 줄)가 stderr로 인쇄된다는 점을 제외하면 파일을 표준 CSV로 변환해야 합니다. 사용 ... >body 2>hdr하고 어딘가에 저장할 수 있습니다 cat hdr body > final_file.csv.

빈 줄 등에 대해서는 특별한 의미가 없습니다. 레코드는 순서에 관계없이 이름이 다른 필드 집합으로 구성된 것으로 간주됩니다.

,또는 를 포함하는 필드는 "내부에 배치되며 "..."내부는 "두 배로 확장하여 이스케이프됩니다 ""(CSV 규칙 사용).

$,=","예를 들어 다음과 같이 변경하여 필드 구분 기호를 조정할 수 있습니다 . $,="|"(또는 $,="\t"탭의 경우). 줄을 제거하면 인용 및 이스케이프를 제거할 수 있습니다 for($k,$v){ ... }.

awksed이 작업은 (in 또는 대신)에서 수행할 수 있습니다. 전체 배열을 한 번에 인쇄할 수 있는 방법이 없고(반복해야 함) 문자열을 분할할 수 없기 tr때문에 조금 더 복잡해질 뿐입니다. awk제한된 수의 필드(스킬을 사용해야 함 substr)

답변2

완전성을 위해 awk- .

-스크립트 awk(우리는 이를 이라고 부름 convert_csv.awk):

#!/bin/awk -f
BEGIN{FS=":";OFS=","}

# Process all non-empty lines
NF>0{
    # Check if the "key" part of the line was not yet encountered, both globally
    # and for the currently processes record.
    # If not encountered globally yet, add to list of headers (=columns).
    new_hdr=1; new_key=1;
    for (i=1; i<=n_hdrs; i++) {if (hdr[i]==$1) new_hdr=0;}
    if (new_hdr) hdr[++n_hdrs]=$1;

    for (key in val) {if (key==$1) new_key=0;}


    # Once no globally new keys are found, consider the "list of headers" as
    # complete and print it as CSV header line.
    if (!new_hdr && !hdr_printed)
    {
        for (i=1;i<=n_hdrs;i++) printf("%s%s", hdr[i], i==n_hdrs?ORS:OFS);
        hdr_printed=1;
    }

    # If the current key was already found in the currently processed record,
    # we assume that a new record was started, and print the data collected
    # so far before collecting data on the next record.
    if (!new_key)
    {
        for (i=1;i<=n_hdrs;i++) printf("%s%s", val[hdr[i]], i==n_hdrs?ORS:OFS);
        delete val;
    }

    # Associate the "value" part of the line with the "key", perform transformations
    # as necessary. Since both the 'gsub()' function used for escaping '"' to '""'
    # and the 'index()' function used to localize ',' return non-zero if an occurence
    # was found, the sum of both return values being > 0 indicates that the field
    # must be quoted.
    quote=gsub("\"","\"\"",$2)+index($2,",");
    if (quote) $2="\""$2"\"";
    val[$1]=$2;
}


# Print the last record. If it was the only record, print the header line, too (this
# is the case if 'new_hdr' is still 'true' at end-of-file).
END {
    if (new_hdr)
    {
        for (i=1;i<=n_hdrs;i++) printf("%s%s", hdr[i], i==n_hdrs?ORS:OFS);
    }

    for (i=1;i<=n_hdrs;i++) printf("%s%s", val[hdr[i]], i==n_hdrs?ORS:OFS);
}

이 함수는 주석에 설명되어 있지만 기본적으로 고유 키 모음을 찾고 행에서 "이미 발견된" 키를 발견하면 레코드가 완료된 것으로 간주한 다음 레코드를 인쇄하고 다음 레코드를 수집하기 위해 임시 버퍼를 지웁니다. . 또한 필드의 특수 문자에 대한 CSV 표준을 준수하기 위해 @mosvy로 표시된 변환을 적용합니다.

전화해

awk -f convert_csv.awk input.txt

관련 정보