AWK 명령의 결과를 새 CSV 파일에 씁니다.

AWK 명령의 결과를 새 CSV 파일에 씁니다.

다음 텍스트가 포함된 전체 파일 목록이 있습니다.

Sun Aug 22 19:00:00 2021
        User-Name = "407359687"
        Acct-Status-Type = Interim-Update
        Acct-Output-Octets = 3263901190
        Acct-Session-Id = "PPP3092201SSG0001006b0a55AABODS"
        Acct-Session-Time = 1146851
        Acct-Output-Gigawords = 15
        Event-Timestamp = "Aug 22 2021 18:55:32 +08"
        Timestamp = 1629630000

내 목표는 중요한 행을 가져와 새 CSV 파일에 저장하는 것입니다. 아래 AWK 명령을 사용하여 텍스트의 값을 정렬하고 있지만 CSV 파일에 쓰는 방법을 모르겠습니다.

awk '{if ($1 == "User-Name")
    {start=1; wholeLine=""; wholeLine = wholeLine$3;}
    if ($1$2$3 =="Acct-Status-Type=Interim-Update"||$1$2$3 =="Acct-Status-Type=Stop")
    {wholeLine=wholeLine","$3;}
    else if ($1$2$3 =="Acct-Status-Type=Start")
    {start=0;wholeLine=""}
    if (($1=="Acct-Output-Octets")&&(start==1))
    {wholeLine=wholeLine","$3;}
    if (($1=="Acct-Session-Id")&&(start==1))
    {wholeLine=wholeLine","$3;}
    if (($1=="Acct-Session-Time")&&(start==1))
    {wholeLine=wholeLine","$3;}
    if (($1=="Acct-Output-Gigawords")&&(start==1)) 
    {wholeLine=wholeLine","$3;} 
    if (($1=="Event-Timestamp")&&(start==1))
    {timeStamp="";timeStamp=$3" "$4" "$5" "$6" "$7;wholeLine=wholeLine","timeStamp}
    if (($1=="Timestamp")&&(start==1))
    {wholeLine=wholeLine","$3;}
    if (($1=="")&&(start==1))
    {start=0;print wholeLine}}' /home/file/detail-20210822

내 예상 CVS 결과는 다음과 같아야 합니다.

"405947674",Interim-Update,1079493624,"PPP3082110SSG000100be4a72AAAk5Y",25440,0,"Aug 22 2021 19:00:43 +08",1629630315

답변1

각 레코드의 8개 필드가 항상 올바른 순서로 존재하고 CSV 파일에서 유효하기 위해 추가 처리가 필요하지 않다고 가정합니다(즉, 추가 인용이나 이스케이프가 필요하지 않음).

sed -n 's/^[^=]*= //p' file | paste -d , - - - - - - - -

그러면 등호 뒤에 공백이 오는 줄(또는 =하위 문자열에 줄의 첫 번째 등호가 포함되지 않은 줄)이 포함되지 않은 줄이 제거되고, 첫 번째 등호 뒤와 공백 앞의 모든 텍스트가 제거됩니다.

paste그런 다음 나머지 데이터의 쉼표로 구분된 8개 열을 만드는 데 사용됩니다 .

샘플 데이터가 포함된 파일에 대해 두 가지 테스트를 실행합니다.

$ sed -n -e 's/^[^=]*= //p' file | paste -d , - - - - - - - -
"407359687",Interim-Update,3263901190,"PPP3092201SSG0001006b0a55AABODS",1146851,15,"Aug 22 2021 18:55:32 +08",1629630000
"407359687",Interim-Update,3263901190,"PPP3092201SSG0001006b0a55AABODS",1146851,15,"Aug 22 2021 18:55:32 +08",1629630000

Start두 번째 열의 모든 행은 결과를 파이핑하여 제거할 수 있습니다 (원본 데이터의 일부를 필터링하기 위해).Acct-Status-Type = Start

awk -F , '$2 != "Start"'

답변2

=레코드를 분리하는 유일한 것은 샘플 입력 상단의 타임스탬프이고 각 레코드에는 모두 동일한 레이블(이름/키/기호 데이터 의 왼쪽)이 포함되어 있다고 가정하여 실제로 파일을 CSV로 변환하는 방법은 다음과 같습니다. :

$ cat tst.awk
BEGIN { OFS="," }
/=/ {
    gsub(/^[[:space:]]+|[[:space:]]+$/,"")
    tag = val = $0
    sub(/[[:space:]]*=.*/,"",tag)
    sub(/[^=]*=[[:space:]]*/,"",val)
    if ( !(tag in tag2val) ) {
        tags[++numTags] = tag
    }
    tag2val[tag] = val
    next
}
NR>1 { prt() }
END { prt() }

function prt(   tagNr, tag, val) {
    if ( !doneHdr++ ) {
        for (tagNr=1; tagNr<=numTags; tagNr++) {
            tag = sanitize(tags[tagNr])
            printf "%s%s", tag, (tagNr<numTags ? OFS : ORS)
        }
    }
    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = tags[tagNr]
        val = sanitize(tag2val[tag])
        printf "%s%s", val, (tagNr<numTags ? OFS : ORS)
    }
    numTags = 0
    delete tag2val
}

function sanitize(inStr,        outStr) {
    outStr = inStr
    if ( outStr ~ ("[" OFS "\"]") ) {
        gsub(/^"|"$/,"",outStr)
        gsub(/"/,"\"\"",outStr)
        outStr = "\"" outStr "\""
    }
    return outStr
}

$ awk -f tst.awk file
User-Name,Acct-Status-Type,Acct-Output-Octets,Acct-Session-Id,Acct-Session-Time,Acct-Output-Gigawords,Event-Timestamp,Timestamp
"407359687",Interim-Update,3263901190,"PPP3092201SSG0001006b0a55AABODS",1146851,15,"Aug 22 2021 18:55:32 +08",1629630000

이것을 파일에 쓰는 것은 다른 명령 출력을 파일에 쓰는 것과 같습니다.

awk -f tst.awk file > output.csv

위의 내용은 입력 값이나 레이블에 줄 바꿈 외에 =, ", ,s 또는 기타 문자가 포함되어 있어도 정확하고 유효한 CSV를 출력합니다.

헤더 행이 실제로 필요하지 않은 경우 함수에서 if ( !doneHdr++ )블록을 제거 하면 됩니다 prt().

답변3

내가 먼저 할게

awk -F= 'NF==2{printf "%s%s",comma,substr($2,2);comma=","} END {printf "\n" }' source > dest

어디

  • -F==구분자 로 사용
  • NF==22개의 필드가 있는 행 선택
  • substr($2,2)선행 공백 제거
  • sourcedest소스 및 대상 파일입니다 .

프로그램을 유지하려면 교체할 수 있습니다.

if (($1=="Acct-Session-Id")&&(start==1))
{wholeLine=wholeLine","$3;}

통과

$1 ~ /Acct-Session-Id/ && (start==1) {wholeLine=wholeLine","substr($2,2);}

@berndbausch가 지적했듯이 둘러싸는 { ... } 를 제거하십시오.

답변4

Raku(이전 Perl_6) 사용

raku -e 'my @array; for lines() {@array.push($_) if /User\-Name/ fff /<!after Event\-> Timestamp/}; 
         @array>>.split(/^^ .+? " = "/, :skip-empty).batch(8).map(*.join(",")).join("\n").put;'

입력 예(@FelixJN 이후):

Sun Aug 22 19:00:00 2021
        User-Name = "407359687"
        Acct-Status-Type = Interim-Update
        Acct-Output-Octets = 3263901190
        Acct-Session-Id = "PPP3092201SSG0001006b0a55AABODS"
        Acct-Session-Time = 1146851
        Acct-Output-Gigawords = 15
        Event-Timestamp = "Aug 22 2021 18:55:32 +08"
        Timestamp = 1629630000
RANDOM ANNOYANCE
AND AN EMPTY LINE

Sun Aug 22 19:00:00 2021
        User-Name = "407359687"
        Acct-Status-Type = Interim-Update
        Acct-Output-Octets = 3263901190
        Acct-Session-Id = "PPP3092201SSG0001006b0a55AABODS"
        Acct-Session-Time = 1146851
        Acct-Output-Gigawords = 15
        Event-Timestamp = "Aug 22 2021 18:55:32 +08"
        Timestamp = 1629630000

예제 출력:

"407359687",Start,3263901190,"PPP3092201SSG0001006b0a55AABODS",1146851,15,"Aug 22 2021 18:55:32 +08",1629630000
"407359687",Interim-Update,3263901190,"PPP3092201SSG0001006b0a55AABODS",1146851,15,"Aug 22 2021 18:55:32 +08",1629630000

OP가 솔루션을 요구했다는 것을 알고 있지만 awkPerl 언어 계열은 텍스트 처리로 가장 잘 알려져 있습니다. 위의 "한 줄짜리" Raku 코드는 fff"트리거" 연산자를 사용하여 두 센티넬 줄 사이의 텍스트를 캡처합니다. 첫 번째는 "사용자 이름" 줄과 일치하고 두 번째는 "타임스탬프" 줄과 일치합니다. <!after Event\->정규 표현식이 "이벤트-타임스탬프" 줄을 잘못 식별하지 않도록 하기 위해 부정 탐색이 사용됩니다.

선택한 행이 푸시된 @array다음 split()원하는 값 왼쪽에 있는 모든 항목을 삭제하는 데 사용됩니다. 레코드는 batch()8개의 그룹(열)으로 구성되며 값은 map()쉼표를 사용하여 호출됩니다 join() . 연속적인 레코드 줄은 개행 문자로 연결됩니다.

두 번째 열의 CSV 행을 제거하려면 Start다음을 통해 위의 단일 행을 파이프하면 됩니다.

raku -ne '.put unless .split(",")[1] eq "Start";'

CSV가 컴퓨팅 생활의 주요 부분이 되려면 여기에서 시작하는 것이 좋습니다. Raku에는 CSV더 복잡한 CSV 사례를 처리하는 데 도움이 되는 많은 모듈이 있습니다 .

https://modules.raku.org/search/?q=CSV
https://raku.org/

관련 정보