Cắt xén cho một khối văn bản với các phần có thể là tùy chọn


8

Tôi có nhiều mục mô tả một sự kiện trong một tệp nhật ký rất lớn, nói A.log . Tôi muốn làm hai điều với các mục sự kiện trong tệp nhật ký:

  1. Đếm số lần xuất hiện của mỗi mục như vậy. (Đây không phải là một yêu cầu bắt buộc nhưng sẽ rất tốt để có.)
  2. Trích xuất các mục thực tế trong một tệp riêng biệt và nghiên cứu chúng sau này.

Một mục sự kiện thông thường sẽ trông giống như sau và sẽ có các văn bản khác giữa chúng. Vì vậy, trong ví dụ dưới đây có hai mục sự kiện , mục đầu tiên chứa hai DataChangeEntry tải trọng và mục thứ hai chứa một DataChangeEntry tải trọng.

    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,  ]

    ]]

Xin lưu ý rằng số lượng ==== DataChangeEntrydòng trong một mục sự kiện có thể thay đổi. Nó cũng có thể hoàn toàn vắng mặt, điều này cho thấy trọng tải sự kiện trống và là một điều kiện lỗi và chắc chắn cũng muốn nắm bắt trường hợp này.

Vì trong trường hợp này, đầu ra của các mục nhập trải dài trên nhiều dòng, tôi sẽ không sử dụng vanilla grep đơn giản. Vì vậy, tôi đang tìm kiếm lời khuyên chuyên gia.

Tái bút

  1. Hãy để tôi rõ ràng hơn về yêu cầu của tôi. Tôi muốn chụp toàn bộ khối văn bản được hiển thị ở trên nguyên văn và tùy ý đếm số lượng phiên bản của các khối như vậy gặp phải. Tùy chọn để đếm số lượng phiên bản là tốt để có nhưng không phải là một yêu cầu bắt buộc.
  2. Nếu giải pháp cho vấn đề là sử dụng awk, tôi muốn lưu tệp awk và sử dụng lại. Vì vậy, xin vui lòng đề cập đến các bước để thực hiện các kịch bản cũng. Tôi biết regex và grep nhưng tôi không quen với sed và / hoặc awk.

Họ có luôn bắt đầu với Data control raising event?
LatinSuD

@LatinSuD vâng, nó luôn bắt đầu với chuỗi đó.
Geek

Tôi nghĩ rằng đây là một công việc dành cho awk, sử dụng (các) biến "máy trạng thái", nhưng bạn nên thêm một số thông tin để nhận trợ giúp về vấn đề này, như mã thông báo chính xác được tìm kiếm và kết quả cuối cùng bạn mong đợi.
Didi Kohen

@DavidKohen Một mục sự kiện bắt đầu bằng mã thông báo "Sự kiện nâng cao kiểm soát dữ liệu" và kết thúc bằng "]]" trong một dòng mới. Tôi muốn tìm hiểu từng trường hợp sự kiện như vậy .
Geek

Tìm những gì về họ? Đếm số lượng của họ? In tất cả? Vui lòng chỉnh sửa câu hỏi của bạn và thêm đầu ra dự kiến ​​mẫu (tốt nhất là với các đầu vào mẫu khác nhau).
Didi Kohen

Câu trả lời:


4

Điều này sẽ làm điều đó tôi hy vọng. Sự kiện đi đến eventstập tin. Và tin nhắn đi đến stdout.

Lưu tệp này vào myprogram.awk (ví dụ):

#!/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
}

Bạn có thể gọi nó theo nhiều cách khác nhau:

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

Đầu ra mẫu:

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

Bạn có thể kiểm tra tất cả các sự kiện cùng nhau trong tệp được gọi eventstrong thư mục làm việc.


Bạn nên tăng bộ đếm sự kiện riêng biệt với tiêu đề sự kiện (hoặc có toán tử trước), điều này làm cho tiêu đề và chân trang hiển thị các số khác nhau và ít đọc hơn.
Didi Kohen

@LatinSuD Tôi không quen với awk. Vì vậy, nếu bạn có thể thêm phần mà tôi cần làm để chạy chương trình trên, nó sẽ rất hữu ích. Đối với tôi, tập tin đầu vào là A.log .
Geek

Để sử dụng tập lệnh này, chỉ cần thay thế inputfile.txt bằng tên tệp của bạn hoặc tốt hơn là xóa mèo và ống dẫn và đặt tên tệp của bạn sau khi trích dẫn đơn.
Didi Kohen

@DavidKohen Tôi muốn lưu tập lệnh này. Vì vậy, nếu tôi lưu điều này như nói findEvents.awk. Tôi có thể thực hiện nó như thế này awk -f findEvents.awk A.logkhông?
Geek

Bạn có thể, nhưng bạn chỉ nên lưu phần trong dấu ngoặc đơn trong tệp đó.
Didi Kohen

2

Một cách tiếp cận rất đơn giản sẽ là

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

Điều này sẽ tạo một tệp riêng cho mỗi mục nhập và in số lượng mục được tìm thấy cho đầu ra tiêu chuẩn.

Giải trình

  • NRlà số dòng hiện tại trong awk.
  • RS="]]"đặt dấu phân cách bản ghi (định nghĩa "đường") thành ]]. Điều này có nghĩa là mỗi mục sẽ được coi là một dòng duy nhất awk.
  • {print > NR".entry"}: cái này in dòng hiện tại (mục) vào một tệp gọi là [LineNumber].entry. Vì vậy, 1.entrysẽ chứa thứ 1, 2.entrythứ hai và như vậy.
  • END{print NR" entries"}: khối END được thực thi sau khi toàn bộ tệp đầu vào được xử lý. Do đó, tại thời điểm đó NRsẽ là số lượng mục được xử lý.

Bạn có thể lưu nó dưới dạng bí danh hoặc biến nó thành một kịch bản như vậy:

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

Sau đó, bạn sẽ chạy tập lệnh (giả sử nó được gọi foo.shvà nằm trong $ PATH của bạn) với tệp đích làm đối số:

foo.sh file

Bạn cũng có thể điều chỉnh tên tập tin đầu ra. Ví dụ: để có các tệp được gọi, hãy [date].[entry number].[entry]sử dụng cái này thay thế:

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

Ở trên giả định rằng tệp nhật ký của bạn chỉ bao gồm các mục "Sự kiện". Nếu đó không phải là trường hợp và bạn có thể có các dòng khác và những dòng đó nên được bỏ qua, thay vào đó hãy sử dụng dòng này:

 #!/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 

Hoặc, như một lớp lót:

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 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.