醜い結果をどのように美しく有用な情報に変えますか?

醜い結果をどのように美しく有用な情報に変えますか?

この醜い結果をどのように美しく便利なデータに変えますか?

出力:

/* ---------- TA#box#AbC_p ---------- */

insert_job: TA#box#AbC_p    job_type: a
#owner: bob
permission: gx
date_conditions: 1
days_of_week: su
start_times: "16:15"
run_window: "16:15-17:30"
description: "Job AbC that runs at 4:15PM on Sundays, and should end before 5:30PM"

    /* ---------- TA#cmd#EfGJob_p ---------- */

    insert_job: TA#cmd#EfGJob_p    job_type: b
    box_name: TA#box#AbC_p
    command: /path/to/shell/script.sh
    machine: vm_machine1
    #owner: alex
    permission: gx
    date_conditions: 2
    run_window: "16:20-16:30"
    description: "job EfG that runs within box AbC"
    term_run_time: 60
    std_out: /path/to/log.log
    std_err: /path/to/err.log
    alarm_if_fail: 1
    profile: /path/to/profile

ちょっと待ってください。 #cmd# ジョブは時々 #box# の下に置かれます。 #cmd# セクションは #box# の下にあるとインデントされます。

私の理想的な出力は次のとおりです。

"Job Name", "Time", "Schedule", "Machine", "Description", "Command"
"TA#box#AbC_p", "16:15", "su", "", "Job AbC that runs at 4:15PM on Sundays, and should end before 5:30PM", ""
"TA#cmd#EfGJob_p", "16:15", "su", "vm_machine1", "job EfG that runs within box AbC", "/path/to/shell/script.sh"

私はawk、perl、およびgrepを試していますが、CSV行を印刷する前に「セクション」に関するすべての情報を一緒に取得することはできません。

答え1

少し怖いsed oneliner:

sed -n  \
# we divide out incoming text to small parts, 
# each one as you mentioned from /---.*box.*/ to /profile/
'/---.*box.*/,/profile/{
     # inside of each part we do following things:
     # if string matches our pattern we extract 
     # the value and give it some identifier (which you
     # can see is "ij", "st" and so on)
     # and we copy that value with identifier to hold buffer,
     # but we don't replace the content of hold buffer
     # we just append (capital H) new var to it
     /insert_job/{s/[^:]*: /ij"/;s/ .*/",/;H};
     /start_times/{s/[^:]*: /st/;s/$/,/;H};
     /days_of_week/{s/[^:]*: /dw"/;s/$/",/;H};
     /machine/{s/[^:]*: /ma"/;s/$/",/;H};
     /description/{s/[^:]*: /de/;s/$/,/;H};
     /command/{s/[^:]*: /co"/;s/$/",/;H};
     # when line matches next pattern (profile)
     # we think that it is the end of our part,
     # therefore we delete the whole line (s/.*//;)
     # and exchange the pattern and hold buffers (x;)
     # so now in pattern buffer we have several strings with all needed variables
     # but all of them are in pattern space, therefore we can remove
     # all newlines symbols (s/\n//g;). so it is just one string 
     # with a list of variables
     # and we just need to move to the order we want,
     # so in this section we do it with several s commands.
     # after that we print the result (p)
     /profile/{s/.*//;x;s/\n//g;s/ij\("[^"]*box[^"]*",\)/\1/;
          s/,\(.*\)st\("[^"]*",\)\(.*ij"[^"]*",\)/,\2\1\3\2/;
          s/\([^,]*,[^,]*,\)\(.*\)dw\("[^"]*",\)\(.*ij"[^"]*",[^,]*,\)/\1\3\2\4\3/;
          s/de/"",/;s/ij/""\n/;
          s/\(\n[^,]*,[^,]*,[^,]*,\)\(.*\)ma\("[^"]*",\)/\1\3\2/;
          s/co\("[^"]*"\),\(.*\)/\2\1/;s/de//;p}
     };
     # the last command just adds table caption and nothing more.
     # note: if you want to add some new commands,
     # add them before this one
     1i"Job Name", "Time", "Schedule", "Machine", "Description", "Command"'

フィールドの順序はボックスごとに異なる可能性があるため作成しましたが、プロファイルは常に最後です。順番が常に同じであれば簡単になります。

答え2

私はPerlを使用するか、少なくともawkを使用します。

perl -ne '
    BEGIN {
        print "\"Job Name\", \"Time\", \"Schedule\", \"Machine\", \"Description\", \"Command\", \"\n";
    }
    chomp; s/^\s+//; s/\s+$//;
    if (($_ eq "" || eof) && exists $fields{insert_job}) {
        print "\"", join("\", \"", @fields{qw(insert_job start_times days_of_week machine description command)}), "\"\n";
        delete @fields{qw(insert_job)};
    }
    if (/^([^ :]+): *(.*)/) {$fields{$1} = $2}
'

説明する:

  • このBEGINブロックはスクリプトの先頭で一度実行され、残りは各入力行に対して実行されます。
  • で始まる行から先頭と末尾のchompスペースを削除します。
  • フィールドがある場合、最初のif行は空の行で実行されます(区切り)。insert_job
  • このdelete行はinsert_jobフィールドを削除します。ある段落から次の段落に流出したくないフィールド名を追加します。
  • 最後のif行にはフィールドが保存されます。

答え3

TXR言語の使用:

@(bind inherit-time nil)
@(bind inherit-sched nil)
@(collect)
@  (all)
@indent/* ---------- @jobname ---------- */
@  (and)
@/ *//* ---------- @nil#@type#@nil ---------- */
@  (end)

@  (bind is-indented @(> (length indent) 0))
@  (gather :vars ((time "") (sched "") (mach "") (descr "") (cmd "")))
@/ */start_times: "@*time"
@/ */days_of_week: @sched
@/ */machine: @mach
@/ */description: "@*descr"
@/ */command: @cmd
@  (until)

@  (end)
@  (cases)
@    (bind type "box")
@    (set (inherit-time inherit-sched) (time sched))
@  (or)
@    (bind type "cmd")
@    (bind is-indented t)
@    (set (time sched) (inherit-time inherit-sched))
@  (end)
@(end)
@(output)
"Job Name", "Time", "Schedule", "Machine", "Description", "Command"
@  (repeat)
"@jobname", "@time", "@sched", "@mach", "@descr", "@cmd"
@  (end)
@(end)

これは非常に幼稚なアプローチです。各レコードから関心のあるすべてのフィールドを抽出し、存在しないフィールドを空白(パラメータのデフォルト値:vars)に置き換えます@(gather)。私たちは仕事の種類(boxまたはcmd)とインデントに焦点を当てています。ボックスを表示すると、一部のボックスプロパティがグローバル変数にコピーされます。インデントされたcmdを表示すると、そのプロパティがコピーされます。 (私たちは以前に誰かが設定したと盲目的に仮定しますbox。)

ランニング:

$ txr jobs.txr jobs
"Job Name", "Time", "Schedule", "Machine", "Description", "Command"
"TA#box#AbC_p", "16:15", "su", "", "Job AbC that runs at 4:15PM on Sundays, and should end before 5:30PM", ""
"TA#cmd#EfGJob_p", "16:15", "su", "vm_machine1", "job EfG that runs within box AbC", "/path/to/shell/script.sh"

出力はカンマ区切りの引用符フィールドのリストですが、データに引用符が含まれる可能性については何もしません。引用符が何らかの方法でエスケープされると、description:当然保存されます。この@*descr表現は貪欲な一致なので、description: "a b"c\"d"出力でそのまま再現される文字を使用しますdescra b"c\"d

このソリューションの利点は、データの例がない場合は、ファイル全体にわたって順序付けられたパターンマッチングを表すため、コード構造からほとんどのデータを推測できることです。収集されるセクションは、ジョブ名を含む行とジョブ名の/* --- ... --- */中央にある2つのハッシュタグの間にタイプフィールドで始まることを示しています。その後、必須の空行があり、その後、他の空行まで属性が収集されます。

関連情報