テキスト処理に sed/awk/perl を使用する

テキスト処理に sed/awk/perl を使用する

このパターンに似たテキスト行がたくさんあります。値と名前を1つの行にグループ化できますか?

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

入力ファイルを 1 行ずつ読み込み、-lnで提供されたスクリプトを実行します-e。空でないすべてのインスタンスがwhile(/(\w+):(\d+)/g)収集され、空で:ないインスタンスがさらに収集されます。かっこ内に含まれているのでこれが$1名前と$2値になります。その後、%k値が配列であるハッシュ配列にプッシュされます。最後に、ハッシュの各キー(名前)とその値の配列を印刷して渡します,

簡潔さを重視する場合は、上記の内容を1行で書くことができます。

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のもう1つのawkソリューションは、スペースで区切られた各データを順番に取得し、配列arrの分割関数を使用して文字に基づいてデータをさらに分割します。次に、文字列を使用してABCなどの文字列をキーとして配列を作成します。印刷します。次に、この配列を繰り返し、キー、:、および文字列で始まる文字列を作成します。その後、印刷してください。

答え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

関連情報