タイムスタンプの最初の行を下のリストに追加します。

タイムスタンプの最初の行を下のリストに追加します。

次のような入力を取得します。

08/22/2019 12:00:58
Name Cans Bucks Puns
Clyde 12 2 79
Sheila 32 16 42
Elmo 44 18 21

08/23/2019 19:00:22
Name Cans Bucks Puns
Clyde 18 21 46
Sheila 37 2 11
Elmo 41 3 10

次のように出力されます。

name=Clyde cans=12 bucks=2 puns=79 ts=1566475258
name=Sheila cans=32 bucks=16 puns=42 ts=1566475258
name=Elmo cans=44 bucks=18 puns=21 ts=1566475258
name=Clyde cans=18 bucks=21 puns=46 ts=1566586822
name=Sheila cans=37 bucks=2 puns=11 ts=1566586822
name=Elmo cans=41 bucks=3 puns=10 ts=1566586822

私はawkを使ってこれを達成しようとしましたが、成功しませんでした(完全に恥ずかしい時間変換を除く)。

私が得た最も近いものは次のとおりです。

ts=08/22/2019 12:00:58
name=Clyde cans=12 bucks=2 puns=79
name=Sheila cans=32 bucks=16 puns=42
name=Elmo cans=44 bucks=18 puns=21
ts=08/23/2019 19:00:22
name=Clyde cans=18 bucks=21 puns=46
name=Sheila cans=37 bucks=2 puns=11
name=Elmo cans=41 bucks=3 puns=10

awkが最高のツールであるかどうかはわかりません。

答え1

awk -F'[/: ]' '{
  if (NF==6){
    ts=mktime($3" "$1" "$2" "$4" "$5" "$6)
    skipheader=1
  }
  else if (NF==0 || skipheader){
    skipheader=0
  }
  else {
    print "name="$1,"cans="$2,"bucks="$3,"puns="$4,"ts="ts
  }
}' file
  • /:別の日付と時刻の部分を取得するには、および空白文字を使用してフィールドを分割します。
  • フィールド数が6つの場合は、タイムスタンプを作成し、ts次のヘッダー行をスキップするようにフラグを設定します。
  • フィールド数が0のskipheader場合、またはフラグが設定されている場合はskipheaderフラグをリセットします。
  • それ以外の場合は、データを印刷します。

出力:

name=Clyde cans=12 bucks=2 puns=79 ts=1566468058
name=Sheila cans=32 bucks=16 puns=42 ts=1566468058
name=Elmo cans=44 bucks=18 puns=21 ts=1566468058
name=Clyde cans=18 bucks=21 puns=46 ts=1566579622
name=Sheila cans=37 bucks=2 puns=11 ts=1566579622
name=Elmo cans=41 bucks=3 puns=10 ts=1566579622

答え2

次のPerlスクリプトは、入力のフィールド数とフィールド名に関係なく機能します。

かかる時間::日付そしてリスト::追加ユーティリティライブラリモジュール。これらの2つは、展開用にすでにパッケージ化されている可能性があります(debianなどsudo apt-get install libtimedate-perl liblist-moreutils-perl)。これらのモジュールを必要としないようにスクリプトを作成することは可能ですが、既存の再利用可能なライブラリコードを必要とするタスクを正確に実行するときにホイールを再構築する必要はありません。

スクリプトは、入力行がスペースの数(たとえば、1つ以上のスペース、タブなど)で区切られていると仮定します。入力がタブで区切られている場合は、行をsplit;に変更しますsplit /\t/;。最初のフィールドの名前にスペースが含まれているか(たとえば)、フィールド名にスペースが含まれている場合は、Firstname Surnameタブ区切り文字を使用することをお勧めします。

たとえば、特定のタイムゾーンをハードコードする必要がある場合は、GMT次の行を変更します。

    $ts = str2time($_);

たとえば、(前の引用符内のスペースに注意してくださいGMT):

    $ts = str2time($_ . ' GMT');
#!/usr/bin/perl

use strict;
use Date::Parse;
use List::MoreUtils qw(pairwise);

my @columns;
my $ts='';

while(<>) {
  s/^\s*|\s*$//g;    #/ strip leading and trailing spaces
  next if (/^$/);    #/ skip empty lines
  chomp;

  # line begins with two digits and a slash? it's a date.
  if (m/^\d\d\//) {
    # get the date and parse it so that we have seconds since the epoch
    $ts = str2time($_);

    # get the next line and split it into column headers
    $_ = readline;
    @columns = split;

  } else {
    # split the current line into @row array
    my @row=split;
    # use pairwise() function from List::MoreUtils module to merge the
    # @columns and @row arrays.
    print join(" ", (pairwise { "$a=$b" } @columns, @row), "ts=$ts"), "\n";
  }

}

出力例:

$ ./reformat.pl input.txt 
Name=Clyde Cans=12 Bucks=2 Puns=79 ts=1566439258
Name=Sheila Cans=32 Bucks=16 Puns=42 ts=1566439258
Name=Elmo Cans=44 Bucks=18 Puns=21 ts=1566439258
Name=Clyde Cans=18 Bucks=21 Puns=46 ts=1566550822
Name=Sheila Cans=37 Bucks=2 Puns=11 ts=1566550822
Name=Elmo Cans=41 Bucks=3 Puns=10 ts=1566550822

注:データ行に列見出しの数より多い列または少ない列がある場合、完全に中断されることはありませんが、異常な出力が生成されます。不足しているフィールドの場合、符号はあるが値はないフィールド名のみを印刷します=(たとえば、入力行にフィールドが2つしかない場合は出力)。フィールドが多い場合は、プレフィックスがPuns=付いた値のみを印刷します(=たとえば、入力行に値が20の追加フィールドがある場合は出力されます)=20

たとえば、入力例に次の3番目のデータブロックがあるとします。

08/23/2019 23:30:01
Name Cans Bucks Puns
Clyde 18 21 46
Sheila 37 2 11
Elmo 41 3 10
Missing 41 3
Extra 41 3 10 20

これにより追加の出力が発生します。

Name=Clyde Cans=18 Bucks=21 Puns=46 ts=1566567001
Name=Sheila Cans=37 Bucks=2 Puns=11 ts=1566567001
Name=Elmo Cans=41 Bucks=3 Puns=10 ts=1566567001
Name=Missing Cans=41 Bucks=3 Puns= ts=1566567001
Name=Extra Cans=41 Bucks=3 Puns=10 =20 ts=1566567001

関連情報