Grepping untuk blok teks dengan bagian-bagian yang bisa opsional

8

Saya memiliki beberapa entri yang menjelaskan peristiwa dalam file log yang sangat besar, katakan A.log . Saya ingin melakukan dua hal dengan entri acara dalam file log:

  1. Hitung jumlah kemunculan setiap entri tersebut. (Ini bukan persyaratan wajib tapi akan menyenangkan untuk dimiliki.)
  2. Ekstrak entri aktual dalam file terpisah dan pelajari nanti.

Entri acara yang khas akan terlihat seperti berikut dan akan memiliki teks lain di antara mereka. Jadi, dalam contoh di bawah ini ada dua entri acara , yang pertama berisi dua DataChangeEntry muatan dan yang kedua berisi satu DataChangeEntry muatan.

    Data control raising event :DataControl@263c015d[[
    #### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1.                         beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58.                                                                                                                         beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
    Filter/Collection Id : 0
    Collection Level     : 0
    Sequence Id             : 616
    ViewSetId            : PatternMatch.LegendTimeAxis_V1_0_SN49
    ==== DataChangeEntry (#1)
    ChangeType           : UPDATE
    KeyPath              : [2014-06-26 06:15:00.0, 0]
    AttributeNames       : [DATAOBJECT_CREATED, COUNTX, QueryName]
    AttributeValues      : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
    AttributeTypes       : [java.sql.Timestamp, java.lang.Integer, java.lang.String,  ]
    ==== DataChangeEntry (#2)
    ChangeType           : UPDATE
    KeyPath              : [2014-06-26 06:15:00.0, 0]
    AttributeNames       : [DATAOBJECT_CREATED, COUNTX, QueryName]
    AttributeValues      : [2014-06-26 06:15:00.0, 9, AverageCallWaitingTimeGreateThanThreshold]
    AttributeTypes       : [java.sql.Timestamp, java.lang.Integer, java.lang.String,  ]

    ]]

someother non useful text
spanning multiple lines 

 Data control raising event :DataControl@263c015d[[
    #### DataChangeEvent #### on [DataControl name=PatternMatch_LegendTimeAxis, binding=.dynamicRegion1.                         beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxisPageDef_beam_project_PatternMatch_dashboard_LegendTimeAxis_taskflow_LegendTimeAxis_beamDashboardLegendTimeAxis_xml_ps_taskflowid.dynamicRegion58.                                                                                                                         beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxisPageDef_beam_project_PatternMatch_view_LegendTimeAxis_taskflow_LegendTimeAxis_beamVizLegendTimeAxis_xml_ps_taskflowid.QueryIterator]
    Filter/Collection Id : 0
    Collection Level     : 0
    Sequence Id             : 616
    ViewSetId            : PatternMatch.LegendTimeAxis_V1_0_SN49
    ==== DataChangeEntry (#1)
    ChangeType           : UPDATE
    KeyPath              : [2014-06-26 06:15:00.0, 0]
    AttributeNames       : [DATAOBJECT_CREATED, COUNTX, QueryName]
    AttributeValues      : [2014-06-26 06:15:00.0, 11, StrAvgCallWaitTimeGreaterThanThreshold]
    AttributeTypes       : [java.sql.Timestamp, java.lang.Integer, java.lang.String,  ]

    ]]

Harap dicatat bahwa jumlah ==== DataChangeEntrybaris dalam entri acara dapat bervariasi. Itu juga bisa benar-benar tidak ada yang akan menunjukkan muatan acara kosong dan merupakan kondisi kesalahan dan pasti ingin menangkap kasus ini juga.

Karena dalam hal ini output dari entri membentang di beberapa baris saya tidak terlalu jauh menggunakan plain vanilla grep. Jadi saya mencari saran ahli.

PS:

  1. Biarkan saya lebih eksplisit tentang kebutuhan saya. Saya ingin menangkap seluruh blok teks yang ditunjukkan di atas kata demi kata dan secara opsional menghitung jumlah instance dari blok yang ditemui. Pilihan untuk menghitung jumlah instance adalah baik untuk dimiliki tetapi bukan persyaratan wajib.
  2. Jika solusi untuk masalah ini menggunakan awk, saya ingin menyimpan file awk dan menggunakannya kembali. Jadi tolong sebutkan langkah-langkah untuk menjalankan skrip juga. Saya tahu regex dan grep tetapi saya tidak terbiasa dengan sed dan / atau awk.
Kutu buku
sumber
Apakah mereka selalu memulai Data control raising event?
LatinSuD
@LatinSuD ya itu selalu dimulai dengan string itu.
Geek
Saya pikir ini adalah pekerjaan awk, menggunakan variabel "mesin negara" (s), tetapi Anda harus menambahkan beberapa informasi lebih lanjut untuk mendapatkan bantuan dengan ini, seperti token yang tepat dicari dan apa yang Anda harapkan dari hasil akhirnya.
Didi Kohen
@DavidKohen Entri acara dimulai dengan "Acara peningkatan kontrol data" token dan berakhir dengan "]]" di baris baru. Saya ingin mencari tahu setiap kejadian seperti itu .
Geek
Temukan bagaimana dengan mereka? Hitung jumlahnya? Cetak semuanya? Harap edit pertanyaan Anda dan tambahkan sampel hasil yang diharapkan (dengan input sampel yang berbeda lebih disukai).
Didi Kohen

Jawaban:

4

Saya harap ini akan melakukannya. Acara pergi ke eventsfile. Dan pesan pergi ke stdout.

Simpan file ini ke myprogram.awk (misalnya):

#!/usr/bin/awk -f

BEGIN {
   s=0;  ### state. Active when parsing inside an event
   nevent=0;  ### Current event number
   printf "" > "events"
}

# Start of event
/^ *Data control raising event/ {
   s=1;
   dentries=0;
   print "*** Event number: " nevent >> "events"
   nevent++
}

# Standard event line
s==1 {
   print >> "events"
}

# DataChangeEntry line
/^ *==== DataChangeEntry/ {
   dentries ++
}

# End of event
s==1 && /^ *\]\]/ {
   s=0;
   print "" >> "events"
   if(dentries==0){
      print "Warning: Event " nevent " has no Data Entries"
   }
}

END {
   print "Total event count: " nevent
}

Anda dapat memohonnya dengan berbagai cara:

  • myprogram.awk inputfile.txt
  • awk -f myprogram.awk inputfile.txt

Output sampel:

Warning: Event 3 has no Data Entries
Total event count: 3

Anda dapat memeriksa semua acara bersama di file yang dipanggil eventsdi direktori kerja.

LatinSuD
sumber
Anda harus menambah penghitung acara secara terpisah dari tajuk acara (atau memiliki operator sebelumnya), ini menyebabkan tajuk dan catatan kaki menunjukkan angka yang berbeda dan kurang dapat dibaca.
Didi Kohen
@LatinSuD Saya tidak terbiasa dengan awk. Jadi jika Anda dapat menambahkan bagian yang perlu saya lakukan untuk menjalankan program di atas akan sangat membantu. Bagi saya file inputnya adalah A.log .
Geek
Untuk menggunakan skrip ini, cukup ganti inputfile.txt dengan nama file Anda, atau lebih baik, hapus cat dan pipe, dan letakkan nama file Anda setelah kutipan tunggal penutup.
Didi Kohen
@ DavidKohen Saya ingin menyimpan skrip ini. Jadi jika saya menyimpan ini sebagai say findEvents.awk. Bisakah saya menjalankannya seperti ini awk -f findEvents.awk A.log:?
Geek
Anda bisa, tetapi Anda harus menyimpan hanya bagian dalam tanda kutip tunggal dalam file itu.
Didi Kohen
2

Pendekatan yang sangat sederhana

awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" file 

Ini akan membuat file terpisah untuk setiap entri dan mencetak jumlah entri yang ditemukan ke output standar.

Penjelasan

  • NRadalah nomor baris saat ini di awk.
  • RS="]]"mengatur pemisah rekaman (apa yang mendefinisikan "garis") menjadi ]]. Ini berarti bahwa setiap entri akan diperlakukan sebagai satu baris oleh awk.
  • {print > NR".entry"}: ini mencetak baris saat ini (entri) ke dalam file bernama [LineNumber].entry. Jadi, 1.entryakan berisi 1, 2.entryyang kedua dan seterusnya.
  • END{print NR" entries"}: blok END dijalankan setelah seluruh file input diproses. Oleh karena itu, pada saat itu NRakan ada jumlah entri yang diproses.

Anda dapat menyimpan ini sebagai alias atau membuatnya menjadi skrip seperti:

#!/usr/bin/env bash
awk '{print > NR".entry"}END{print NR" entries"}' RS="]]" "$1"

Anda kemudian menjalankan skrip (dengan asumsi itu dipanggil foo.shdan berada di $ PATH Anda) dengan file target sebagai argumen:

foo.sh file

Anda juga dapat mengubah nama file output. Misalnya, agar file dipanggil [date].[entry number].[entry]gunakan ini sebagai gantinya:

#!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{print > d"."NR".entry"}END{print NR" entries"}' RS="]]" d="$date" "$1"

Di atas mengasumsikan bahwa file log Anda secara eksklusif terdiri dari entri "Acara". Jika bukan itu masalahnya, dan Anda bisa memiliki baris lain, dan baris itu harus diabaikan, gunakan ini sebagai gantinya:

 #!/usr/bin/env bash
date=$(date +%Y%m%d)
awk '{
        if(/\[\[/){a=1; c++;}
        if(/\]\]/){a=0; print > d"."c".entry"}
        if(a==1){print >> d"."c".entry"}
}' d="$date" file 

Atau, sebagai one-liner:

awk '{if(/\[\[/){a=1; c++;}if(/\]\]/){a=0; print > d"."c".entry"}if(a==1){print >> d"."c".entry"}}' d=$(date +%Y%m%d) file 
terdon
sumber