オプションのユニークな出力を提供するために、awkの2つのモード間のテキスト処理

オプションのユニークな出力を提供するために、awkの2つのモード間のテキスト処理

次の入力ファイルがあります。

Policy Name:       KE15-LOCALHOST-APP-RADIX-DAILY

  Policy Type:         Standard
  Active:              yes
  Include:  /appussd
            /home/ussd2ke
            /var/log
            /etc
            /usr

  Schedule:              Montlhy_Full
    Type:                Full Backup
    PFI Recovery:        0
    Maximum MPX:         16
    Retention Level:     5 (3 months)
    Daily Windows:
          Sunday     00:00:00  -->  Sunday     07:00:00
          Monday     00:00:00  -->  Monday     07:00:00
          Tuesday    00:00:00  -->  Tuesday    07:00:00
          Wednesday  00:00:00  -->  Wednesday  07:00:00
          Thursday   00:00:00  -->  Thursday   07:00:00
          Friday     00:00:00  -->  Friday     07:00:00
          Saturday   00:00:00  -->  Saturday   07:00:00

  Schedule:              Weekly_Full
    Type:                Full Backup
    PFI Recovery:        0
    Maximum MPX:         16
    Retention Level:     3 (1 month)
    Daily Windows:
          Wednesday  00:00:00  -->  Wednesday  10:00:00

  Schedule:              Daily_Inc
    Type:                Differential Incremental Backup
    PFI Recovery:        0
    Maximum MPX:         16
    Retention Level:     2 (3 weeks)
    Daily Windows:
          Sunday     01:00:00  -->  Sunday     16:00:00
          Monday     01:00:00  -->  Monday     16:00:00
          Tuesday    01:00:00  -->  Tuesday    16:00:00
          Wednesday  01:00:00  -->  Wednesday  16:00:00
          Thursday   01:00:00  -->  Thursday   16:00:00
          Friday     01:00:00  -->  Friday     16:00:00
          Saturday   01:00:00  -->  Saturday   16:00:00

これで、カンマと;で区切られた(計画の下)、保存レベル、毎日のウィンドウなど、さまざまな種類のペアが必要です。複数のアイテムの場合。

私が試したコマンドは次のとおりです。問題は毎日の窓にありました。途中でデータを取得し、毎日のウィンドウ行を削除できました。これで曜日の名前を削除し、一意の期間のみを希望します。

awk '
  BEGIN { SEP = "" }
  $1 == "Type:" { $1 = ""; T = T SEP $0 }
  $1 == "Retention" && $2 == "Level:" {
    sub(/^.*\(/," ")
    sub(/\).*/,"")
    L = L SEP $0
    if (SEP == "") {
      SEP = ";"
    }
  }
  /Daily Windows:/,/^$/ {
  sub(/^.*Daily.*/,"")
  sub(/^[^A-Z][a-z]+y$/,"")
  S = S SEP $0}
  END {
  sub(/^ */,"",T)
  print T "," L "," S
}'

出力は次のとおりです。

Full Backup; Full Backup; Differential Incremental Backup, 3 months; 1 month; 3 weeks,;;          Sunday     00:00:00  -->  Sunday     07:00:00;          Monday     00:00:00  -->  Monday     07:00:00;          Tuesday    00:00:00  -->  Tuesday    07:00:00;          Wednesday  00:00:00  -->  Wednesday  07:00:00;          Thursday   00:00:00  -->  Thursday   07:00:00;          Friday     00:00:00  -->  Friday     07:00:00;          Saturday   00:00:00  -->  Saturday   07:00:00;;;          Wednesday  00:00:00  -->  Wednesday  10:00:00;;;          Sunday     01:00:00  -->  Sunday     16:00:00;          Monday     01:00:00  -->  Monday     16:00:00;          Tuesday    01:00:00  -->  Tuesday    16:00:00;          Wednesday  01:00:00  -->  Wednesday  16:00:00;          Thursday   01:00:00  -->  Thursday   16:00:00;          Friday     01:00:00  -->  Friday     16:00:00;          Saturday   01:00:00  -->  Saturday   16:00:00

ただし、希望の出力は次のとおりです。

Full Backup; Full Backup; Differential Incremental Backup, 3 months; 1 month; 3 weeks, 00:00:00  -->  07:00:00; 00:00:00  -->  10:00:00; 01:00:00  -->  16:00:00

答え1

:オプションのコロンとFS()で少なくとも2つのスペースを使用すると、余分なスペースと呼ばれる面倒なFS = ":? *"問題を経験することなく、この操作に使用される主なフィールドのほとんどを分離できるようになります。

$ cat t20.awk
BEGIN { FS=":?   *"; OFS = ", "; SEP = "; "; }

# if $2 is "Type", append $3 to T
$2 == "Type" { T = (T ? T SEP : "") $3;}

# if $2 is "Retention Level", append sub-string in parenthesis to L
$2 == "Retention Level" && match($0, /\(.*?\)/) {
    L = (L ? L SEP : "") substr($0, RSTART+1, RLENGTH-2)
}

# in Daily window block, skip all line without " --> "
# use an associative array "a" to make sure unique time range
/Daily Windows:/,/^\s*$/ {
    if (!/ --> /) next
    key = $3 " --> " $6
    if (!a[key]++) S = (S ? S SEP : "") key
}

END { print T, L, S }

メモ:

  1. では、接続の場合と同様に、文字列を連結するときに先行するSEPを回避するためにS = (S ? S SEP : "") keyトリプルを(S ? S SEP : "")使用します。TL

  2. では、削除先行をsubstr($0, RSTART+1, RLENGTH-2)使用し、両方の角かっこを削除します。RSTART+1(RLENGTH-2

コードを実行してください:

$ awk -f t20.awk file.txt
#Full Backup; Full Backup; Differential Incremental Backup, 3 months; 1 month; 3 weeks, 00:00:00 --> 07:00:00; 00:00:00 --> 10:00:00; 01:00:00 --> 16:00:00

修正する:

コメントに記載されている内容に基づいて、Daily Windowsコードのこの部分を次のように調整しました。

  • ロゴを追加しましたdw_on開始と終了を識別するために毎日の窓詰まった。dw_on == 1このパターンで一致するすべての行を確認する必要があります。次の空行が検出されるたびに、このフラグは次にリセットされます。/ --> /S0/^\s*$/
  • 変数を追加しましたcnt_DW数量を計算する毎日の窓各スケジュールの項目です。これはDaily Windows各ブロックの開始時にリセットされます。

ハッシュ(連想配列)によって一意性が維持されます。、各ブロックが起動するとリセットされますDaily Windows。このハッシュのキーはkey = $3 " --> " $6検索したいウィンドウです。構文:if (!a[key]++) S = (S ? S SEP : "") key以下と同じ

  if (!a[key]) { 
      a[key] = a[key] + 1
      S = (S ? S SEP : "") key 
  }

したがって、(a [key] = "")以前に見たことがない場合にのみ、キーkeyにaを追加できますS。 2番目にすでに存在する同じキーを処理すると、上記a[key]==1のコードブロックはスキップされます。これはawk一意性を検証する一般的な方法の1つです。

$ cat t20.1.awk
BEGIN { FS=":?   *"; OFS = ", "; SEP = "; "; }

# if $2 is "Type", append $3 to T
$2 == "Type" { T = (T ? T SEP : "") $3;}

# if $2 is "Retention Level", append sub-string in parenthesis to L
$2 == "Retention Level" && match($0, /\(.*?\)/) {
    L = (L ? L SEP : "") substr($0, RSTART+1, RLENGTH-2)
}

/Daily Windows:/ {
    # turn on the dw_on flag and reset cnt_DW (number of DW entries in a section)
    dw_on = 1; cnt_DW=0;
    # reset the hash 'a' for uniqueness check
    # if you need the uniqueness across all Schedules, then comment it out
    delete a; 
    next;
}

# if dw_on flag is true, i.e. "dw_on == 1"
dw_on {
    # match " --> ", then increase cnt_DW, check the unique window
    # and then append qualified entry to "S"
    if (/ --> /) {
        cnt_DW++
        key = $3 " --> " $6
        if (!a[key]++) S = (S ? S SEP : "") key
    # else if EMPTY line, reset dw_on flag, if cnt_DW is 0, append "No Window" to S
    } else if (/^\s*$/) {
        dw_on = 0;
        if (!cnt_DW) S = (S ? S SEP : "") "No Window"
    }
}

END { 
    # last Schedule section does not have a EMPTY line, so we will need
    # to check up cnt_DW in the last Schedule section in "END" block
    if(dw_on && !cnt_DW) S = (S ? S SEP : "") "No Window";

    # print the result.
    print T, L, S 
}

上記のコードをテストするために、元のデータを次のように少し変更しました。

  1. Daily WindowsSchedulePart IIから別のアイテムを削除しました。
  2. Friday 00:00:00 --> Friday 07:00:00最初のスケジュールの行をFriday 01:00:00 --> Friday 16:00:003 番目のスケジュールセクションの同じ行に置き換えます。

したがって、1日目には固有窓が2つあり、2日程には窓がなく、3日程には固有窓が1つがあり、1日頂窓と同じです。

上記のデータで更新されたコードを実行すると、次のような結果が得られます。

awk -f t20.1.awk file.txt 
#Full Backup; Full Backup; Differential Incremental Backup, 3 months; 1 month; 3 weeks, 00:00:00 --> 07:00:00; 01:00:00 --> 16:00:00; No Window; 01:00:00 --> 16:00:00

01:00:00 --> 16:00:00異なるタイムラインにあるため、2つがあることに注意してください。最後のエントリを削除するには、コードに表示されている行を01:00:00 --> 16:00:00コメントアウトすると、次のような結果が得られます。delete a

#Full Backup; Full Backup; Differential Incremental Backup, 3 months; 1 month; 3 weeks, 00:00:00 --> 07:00:00; 01:00:00 --> 16:00:00; No Window

答え2

次の操作ですべての操作を実行できますawk

awk -F'(: *|[)(])' '
    /^ *Type/     { type=type==""?$2 : type ";" $2 }
    /^ *Retention/{ Retention=Retention==""?$3 : Retention ";" $3}
    /^ *Wednesday/{ gsub(/ +Wednesday/,"",$0); day=day==""?$0 : day ";" $0}
END{ print type, Retention, day }' OFS=, infile

/ ... /フィールド値をより正確に一致させるには、基準セクションを調整する必要があります。

出力は期待どおりです。

関連情報