텍스트 처리를 위해 sed/awk/perl 사용

텍스트 처리를 위해 sed/awk/perl 사용

이 패턴과 유사한 텍스트 줄이 많이 있습니다. 값과 이름을 하나의 행으로 그룹화할 수 있나요?

ABCDEFG_10_node10:2154  ABCDEFG_10_node10:54
ABCDEFG_10_node10:2254  ABCDEFG_10_node10:64
ABCDEFG_10_node10:410 ABCDEFG_10_node10:10
ABCDEFG_10_node10:210 ABCDEFG_10_node10:10 
ABCDEFG_10_node10:365
ABCDEFG_10_node10:890
ABCDEFG_10_node10:741
XXYZZ_71_node2:24: XXYZZ_71_node2:504:
X3y5z_53_node1:664: X3y5z_53_node1:990:
RCTY_11_node2:224: RCTY_11_node2:234:

예상 출력:

ABCDEFG_10_node10: 2154,2254,410,210,365,890,741,54,64,10,10
XXYZZ_71_node2: 24,504
X3y5z_53_node1: 664,990
RCTY_11_node2: 224,234

저는 AIX를 사용하고 있습니다. 어떻게 해야 하나요?

답변1

Perl 접근 방식(순서는 중요하지 않다고 가정):

$ perl -lne 'while(/(\w+):(\d+)/g){
                push @{$k{$1}},$2
             } 
             END{
                print "$_: " . join ",", @{$k{$_}} for keys %k
             }' file 
ABCDEFG_10_node10: 2154,54,2254,64,410,10,210,10,365,890,741

입력 파일을 한 줄씩( -ln) 읽고 에 의해 제공된 스크립트를 실행합니다 -e. 비어 있지 않은 모든 인스턴스가 while(/(\w+):(\d+)/g)수집된 다음 :비어 있지 않은 인스턴스가 더 많이 수집 됩니다 . 괄호 안에 담겨 있으므로 이것이 $1이름과 $2값이 됩니다. 그런 다음 %k값이 배열인 해시 배열로 푸시됩니다 . 마지막으로 해시의 각 키(이름)와 해당 값의 배열을 인쇄하고 를 전달합니다 ,.

간결함을 중시한다면 위의 내용을 한 줄로 작성할 수 있습니다.

perl -lne 'while(/(\S+):(\S+)/g){push @{$k{$1}},$2}}{$"=",";print"$_: @{$k{$_}}" for keys%k' file

가독성을 넘어서:

perl -nE'push@{$k{$1}},$2while/(\w+):(\d+)/g}{$"=",";say"$_: @{$k{$_}}"for keys%k' file

답변2

해결책:

awk -F':|[[:space:]]+' '{ 
         a[$1]=a[$1]? a[$1]","$2:$2; if(NF==4) b[$3]=b[$3]? b[$3]","$4:$4 
     }
     END{ for(i in a) printf "%s: %s%s\n",i,a[i],(i in b)? ","b[i]:"" }' file

  • -F':|[[:space:]]+'- 복잡한 필드 구분 기호

  • a[$1]=a[$1]? a[$1]","$2:$2- 각 고유 이름에 대한 그룹 값ABCDEFG...

  • if(NF==4) b[$3]=b[$3]? b[$3]","$4:$4- 추가 오른쪽 부분이 있는 경우 - 값을 추가 배열로 그룹화합니다.b


산출:

ABCDEFG_10_node10: 2154,2254,410,210,365,890,741,54,64,10

----------

값의 순서가 중요하지 않은 경우 위 방법을 약간 단순화할 수 있습니다.

awk -F':|[[:space:]]+' '{ 
        a[$1]=a[$1]? a[$1]","$2:$2; if(NF==4) a[$3]=a[$3]? a[$3]","$4:$4 
     }
     END{ for(i in a) print i":",a[i] }' file

답변3

awk '{ for (i=1;i<=NF;i++) { split($NF,arr,":");if (dat[arr[1]]=="") { dat[arr[1]]=arr[2] } else { dat[arr[1]]=dat[arr[1]]","arr[2] } } } END { for ( i in dat ) { print i": "dat[i] } }' filename

Roman의 또 다른 awk 솔루션은 공백으로 구분된 각 데이터를 차례로 가져온 다음 배열 arr의 분할 함수를 사용하여 문자를 기반으로 데이터를 추가로 분할합니다. 그런 다음 문자열을 사용하여 ABC와 같은 문자열을 키로 사용하여 배열을 만듭니다. 인쇄합니다. 그런 다음 이 배열(dat)을 반복하고 키, : 및 문자열로 시작하는 문자열을 만듭니다. 그런 다음 인쇄하세요.

답변4

Raku(이전 Perl_6) 사용

raku -e 'say .key, " => ", .value.words[1,3,5...*] for lines.split(/<[:\s]>/, :skip-empty).rotor(2).classify( *.[0]);'

입력 예:

ABCDEFG_10_node10:2154  ABCDEFG_10_node10:54
ABCDEFG_10_node10:2254  ABCDEFG_10_node10:64
ABCDEFG_10_node10:410 ABCDEFG_10_node10:10
ABCDEFG_10_node10:210 ABCDEFG_10_node10:10 
ABCDEFG_10_node10:365
ABCDEFG_10_node10:890
ABCDEFG_10_node10:741
XXYZZ_71_node2:24: XXYZZ_71_node2:504:
X3y5z_53_node1:664: X3y5z_53_node1:990:
RCTY_11_node2:224: RCTY_11_node2:234:

예제 출력:

XXYZZ_71_node2 => (24 504)
RCTY_11_node2 => (224 234)
ABCDEFG_10_node10 => (2154 54 2254 64 410 10 210 10 365 890 741)
X3y5z_53_node1 => (664 990)

즉, lines읽고, 파괴적으로 split읽고 (빈 요소를 생략하여 :) , 2개의 요소마다 (연결)하고, 각 쌍의 첫 번째 요소를 통해 -ing합니다. [ 의도를 명확히 하기 위해 전화를 할 수도 있었지만 어쨌든 라쿠는 옳은 일을 했습니다.]\s:skip-emptyrotorclassify.classify( *.[0].unique)

OP가 자신의 게시물에 지정된 형식을 정말로 원하는 경우 =>통화가 끝날 때 통화를 대체하고 추가하십시오 :. 따라서 이전의 전체 부분은 다음과 같습니다.join.valueforsay .key, ": ", .value.words[1,3,5...*].join(",")

출력 예(2):

X3y5z_53_node1: 664,990
RCTY_11_node2: 224,234
ABCDEFG_10_node10: 2154,54,2254,64,410,10,210,10,365,890,741
XXYZZ_71_node2: 24,504

https://docs.raku.org/routine/classify
https://raku.org

관련 정보