CSV 파일: 각 값의 첫 번째 패턴을 기준으로 값을 그룹화하고 합계합니다.

CSV 파일: 각 값의 첫 번째 패턴을 기준으로 값을 그룹화하고 합계합니다.

저는 bash를 사용하여 CSV 파일에서 필드를 찾고, 그룹화하고, 합계하는 스크립트를 만들고 있습니다. 각 행에는 쉼표로 구분된 필드가 있으며 각각 유사한 규칙을 따릅니다. 쉼표로 구분된 각 필드에는 숫자 값, 등호(=), 영숫자 값이 차례로 표시됩니다. "(숫자)="는 한 줄에 나타날 수도 있고 그렇지 않을 수도 있으며, 그럴 경우 필드 위치가 다를 수 있지만 한 줄에 한 번만 나타납니다. 또한 등호 뒤의 값 길이도 달라집니다.

내 목표의 예가 최고입니다. CSV 파일:

35=D,11=ABCD1,1=ABC,55=XYZ,38=100,40=P,18=M,54=1,59=0,10=111
35=D,11=ABCD2,1=ABC,55=XYZ,40=P,18=M,38=200,54=1,44=10.00,59=0,10=133
35=D,11=ABCD3,1=ABC,55=XYZ,40=P,18=M B,54=1,38=300,44=10.00,59=0,110=200,10=113
35=D,11=ABCD4,1=ABC,55=XYZ,38=400,40=P,18=M B F,54=1,44=10.00,59=0,110=300,10=144
35=D,11=ABCD5,1=ABC,55=ZYX,38=300,40=2,54=1,44=10.00,59=3,10=132
35=D,11=ABCD6,1=ABC,55=ZYX,38=100,40=1,18=C,54=2,59=3,10=131

"38="로 시작하는 모든 필드를 식별한 다음 "=" 뒤의 모든 숫자 값을 합하고 각 "55="로 그룹화하는 스크립트를 원합니다. 각 줄에는 "38=" 및 "55="가 있습니다.

위 파일을 사용한 출력은 다음과 같습니다(정렬은 선택 사항).

55=XYZ 38=1000
55=ZYX 38=400

답변1

밀러를 사용하여http://johnkerl.org/miller/doc, 지금부터input.csv

35=D,11=ABCD1,1=ABC,55=XYZ,38=100,40=P,18=M,54=1,59=0,10=111 35=D,11=ABCD2,1=ABC,55=XYZ,40=P,18=M,38=200,54=1,44=10.00,59=0,10=133 35=D,11=ABCD3,1=ABC,55=XYZ,40=P,18=M B,54=1,38=300,44=10.00,59=0,110=200,10=113 35=D,11=ABCD4,1=ABC,55=XYZ,38=400,40=P,18=M B F,54=1,44=10.00,59=0,110=300,10=144 35=D,11=ABCD5,1=ABC,55=ZYX,38=300,40=2,54=1,44=10.00,59=3,10=132 35=D,11=ABCD6,1=ABC,55=ZYX,38=100,40=1,18=C,54=2,59=3,10=131

그리고 달리는 중

mlr --ofs " " unsparsify then stats1 -a sum -f 38 -g 55 then rename 38_sum,38 input.csv

당신은 할 것

55=XYZ 38=1000 55=ZYX 38=400

답변2

Steeldriver가 나를 좀 이겼지만 난 알아냈어

perl -F'[=,]' -lane '
        %row = @F;
        $sum{$row{55}} += $row{38};
    }{ 
        print "$_ = $sum{$_}" for keys %sum
' file.csv
XYZ = 1000
ZYX = 400

답변3

여기에 해결책이 있습니다 awk.

awk -F, '{for(a=1;a++<=NF;){
          if($a~/^55=/){l=$a}
          if($a~/^38=/){b[l]+=substr($a,4)}
         }}END{for(x in b){print x,"38="b[x]}}' inp
  • for(a=1;a++<=NF;){- 쉼표로 구분된 각 필드를 반복합니다.
  • if($a~/^55=/){l=$a}- 다음으로 시작하는 필드를 찾으면 55=이를 변수에 저장합니다.l
  • if($a~/^38=/){b[l]+=substr($a,4)}- 다음으로 시작하는 필드를 찾으면 변수를 키로 사용하여 38=다음 값을 가져와 =배열에 누적합니다 .bl
  • }}END{for(x in b){print x,"38="b[x]}}- 배열의 내용만 인쇄

답변4

어때요?

awk -F, '
        {for (i=1; i<=NF; i++)  {split ($i, T, "=")
                                 if (T[1] == 55) IX = T[2]
                                 if (T[1] == 38) NM = T[2]
                                }
         SUM[IX] += NM
        }
END     {for (s in SUM) print "55=" s, "38=" SUM[s]
        }
' file
55=ZYX 38=400
55=XYZ 38=1000

모든 필드를 반복하여 관련 필드를 찾고, T배열로 분할하고, 55찾은 경우 인덱스를 추출하고, 38찾은 경우 합계를 추출합니다. 루프가 끝나면 합산이 수행됩니다. END섹션 에는 모든 요약 값과 해당 색인이 표시됩니다.

관련 정보