マルチラインパターン/データ抽出

マルチラインパターン/データ抽出

約100,000個のファイルに次のヘッダーがあります。各行を個別に抽出し、各レコードをExcelにマージしたので、時間が足りなくなり、データを抽出する便利な方法を探しています。

X-RSMF-Generator:RSMFジェネレータのサンプルライブラリ

X-RSMFバージョン:1.0.0

X-RSMFイベント数:53

X-RSMF-開始日:2022-09-20T04:33:11-04:00

X-RSMF終了日:2022-09-20T16:47:56-04:00

X-RSMF-グループID:GRP000000118

X-RSMF補助グループID:GRP000000118_D_20220920

X-RSMFインクルードが削除されました:間違った

X-RSMF-アプリケーション:ネイティブメッセージ

X-RSMF参加者:1人称<5156242756> 2人称、2人称

サム[Eメール保護]<21243210277> 4人*** <345278652345>

MIMEバージョン:1.0

すべてのファイルにすべての行が存在するわけではなく、最後のフィールドに複数の行を含めることができます。 MIME バージョン: 1.0 - 利用できるようです。MIMEバージョン:1.0停止で。また、各項目行のデータのみが必要です。 ":" (コロン空白) 前の内容はすべてフィールドヘッダーなので無視できます。

私は各ラインとパイプをAWKに接続できると思いながらsedを使い始めました。各柱を作ります。

#!/bin/sh

shopt -s nullglob
FILES=/mnt/c/Temp/rsmf/*.rsmf

for f in $FILES

do
    #echo "Processing $f"
    sed -rn \
    -e '/^X-RSMF-BeginDate:/{
        s/X-RSMF-BeginDate: //
        s/T/ /
        s/-0[45]:00/ /
        s/X-RSMF-Application://
        h
        #p
        }' \
    -e '/^X-RSMF-EndDate:/{
        s/X-RSMF-EndDate: //
        s/T/ /
        s/-0[45]:00/ /
        H
        #p
        }' \
     -e '/^X-RSMF-GroupID:/{
        s/X-RSMF-GroupID: //
        H
        x
        s/\r\n//gp
        }' \
         $f
done

結果 -

2022-10-05 12:54:27 2022-10-05 12:54:27 GRP000000001
2022-10-05 11:48:18 2022-10-05 11:48:18 GRP000000002

この問題を議論する前に、この特定のプロジェクトのベストプラクティスとケースに関するアドバイスを求めたいと思います。

アイデア? ?

答え1

そして:

awk -F': ' 'BEGIN{ORS=" "}$1=="MIME-Version"{exit}{print $2}END{print "\n"}' file    

答え2

以下はやや昔ながらの無差別的なアプローチです。おそらくより良い方法があります。 (しかし、あなたのデータについてもっと知っておく必要があり、なぜExcelに言及したのかを知る必要があります。サンプルデータとして機能します。

これにより、必要な数の入力ファイルを処理できます。

スペースの代わりにTAB(\tまたはCtrl-Iまたは)を出力フィールド区切り文字として使用するように作成されました。^Iフィールドデータにスペースを含めることができるため、

#!/usr/bin/perl

while (<>) {
  chomp;
  s/^\s*|\s*$//g;  # strip any leading and trailing whitespace
  next if /^$/;    # ignore all blank lines

  # split input line into @F array
  # $F[0] will contain the field name and
  # $F[1] will contain the field data
  # The field separator is a quite-forgiving zero-or-more spaces followed by
  # a colon followed by one-or-more spaces. This should cope with most minor
  # variants caused by manual extraction from Excel. 
  my @F = split /\s*:\s+/;

  # print the data at end of each input record (file)
  if (/^MIME-Version/) {
    # add space-separated @participants array to end of @record array
    push @record, join(" ", @participants);

    # print @record array, tab-separated
    print join("\t", @record), "\n";

    # clear both arrays, ready for next input file
    @record=();
    @participants=();
    next;
  };

  # fix up the date format
  if (/^X-RSMF-(Begin|End)Date/) {
    $F[1] =~ s/T/ /;
    $F[1] =~ s/-0[45]:00$//;
  };

  if (/^X-RSMF-Participants/) {
    # participants need to be handled differently because this field can
    # be multi-line.  Store in a separate @participants array
    push @participants, $F[1];

  } elsif ($#F == 0) {
    # lines without a field name get added to @participants array
    push @participants, $_;

  } else {
    # all other fields get added to @record array
    push @record, $F[1];
  }
}

たとえば、ファイルに保存してrsmf2tab.pl実行可能にしてからchmod +x rsmf2tab.pl実行します。

./rsmf2tab.pl /mnt/c/Temp/rsmf/*.rsmf

または、.rsmfファイルが複数のサブディレクトリにある場合:

find /mnt/c/Temp/rsmf/ -name '*.rsmf' -exec /path/to/rsmf2tab.pl {} +

サンプル出力は、サンプルデータ(file1.rsmfとfile2.rsmfなど)の2つのコピーを入力として使用し、パイプを介してタブを次のcat -Aように表示します^I

$ ./rsmf2tab.pl *.rsmf | cat -A
RSMF Generator Sample Library^I1.0.0^I53^I2022-09-20 04:33:11^I2022-09-20 16:47:56^IGRP000000118^IGRP000000118_D_20220920^IFalse^INative Messages^IPerson One <5156242756> Person two, Person three [email protected] <21243210277> Person four <345278652345>$
RSMF Generator Sample Library^I1.0.0^I53^I2022-09-20 04:33:11^I2022-09-20 16:47:56^IGRP000000118^IGRP000000118_D_20220920^IFalse^INative Messages^IPerson One <5156242756> Person two, Person three [email protected] <21243210277> Person four <345278652345>$

しかし、あなたは本物FILE=/mnt/c/Temp/rsmf/*.rsmf私はもはやあなたの後継者になりたくありませんfor f in $FILES。ファイルに空白文字が含まれていると中断されます。とにかく、これは必要ありません。単に実行したりfor f in /mnt/c/Temp/rsmf/*.rsmf(実行中の項目に応じて)ループを使用せずに、実行中のコマンドにすべてのファイル名引数を渡すだけです。

関連情報