Làm cách nào để lấy văn bản từ phạm vi ngày sử dụng grep / sed trong tệp văn bản lớn?


9

Tôi có văn bản tệp lớn (gần 3 GB) - đó là tệp nhật ký. Tôi muốn nhận các dòng văn bản tương ứng với một phạm vi ngày từ tệp này, từ ngày 13 tháng 7 đến ngày 19 tháng 7. Định dạng nhật ký của tôi là:

2016-07-12 < ?xml version>
2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>
2016-07-20 < ?xml version>
sample text sample text
sample text sample text
sample text sample text
2016-07-20 < ?xml version>
sample text sample text
2016-07-20 < ?xml version>

vì vậy sau grep/ sednó sẽ là đầu ra như thế này:

2016-07-13 < ?xml version>
2016-07-18 < ?xml version>
2016-07-18 < ?xml version>
2016-07-19 < ?xml version>

Làm thế nào tôi có thể nhận được điều này?


2
Bạn có chắc là bạn có nghĩa là tháng sáu ? Tất cả các ngày trong tệp nhật ký mẫu của bạn là vào tháng 7 và mẫu đầu ra mong muốn ngụ ý bạn có nghĩa là sau này.
David Foerster

Câu trả lời:


13

Với grepnếu bạn biết số dòng bạn muốn, bạn có thể sử dụng tùy chọn bối cảnh -Ađể in dòng sau mô hình

grep -A 3 2016-07-13 file

điều đó sẽ cung cấp cho bạn dòng với 2013-07-13 và 3 dòng tiếp theo

với sedbạn có thể sử dụng ngày để phân định như thế này

sed -n '/2016-07-13/,/2016-07-19/p' file

sẽ in tất cả các dòng từ dòng đầu tiên với 2016-07-13 cho đến và bao gồm cả dòng đầu tiên với 2016-07-19. Nhưng điều đó giả định rằng bạn chỉ có một dòng với 2016-07-19 (nó sẽ không in dòng tiếp theo). Nếu có nhiều dòng sử dụng ngày tiếp theo thay vào đó và sử dụng dđể xóa đầu ra khỏi nó

sed -n '/2016-07-13/,/2016-07-20/{/2016-07-20/d; p}' file


4

awk giải pháp:

$ awk '/^2016-07-13.*/,/2016-07-19.*/'  input.txt                                   
2016-07-13 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-18 < ?xml version> 
2016-07-19 < ?xml version> 

Về cơ bản in bất kỳ dòng nào từ dòng bắt đầu 2016-07-13đến dòng bắt đầu bằng2016-07-19


4

Tất cả các câu trả lời hiện tại khác dựa trên thực tế là các mục nhập tệp nhật ký được sắp xếp theo thứ tự thời gian hoặc thực tế là phạm vi ngày có thể được khớp dễ dàng với các biểu thức thông thường. Nếu bạn muốn một giải pháp chung chung hơn, chúng ta cần thực hiện thêm một số chương trình.

Tôi trình bày tập lệnh GNU AWK này:

#!/usr/bin/gawk -f
BEGIN {
    starttime = mktime(starttime)
    endtime = mktime(endtime)
}

func in_range(n, start, end) {
    return start <= n && n < end
}

match($0, /^([0-9]{4})-([0-9]{2})-([0-9]{2})\s/, m) &&
    in_range(mktime(m[1] " " m[2] " " m[3] " 00 00 00"), starttime, endtime)

Bạn cung cấp thời gian bắt đầu và kết thúc thông qua các biến starttimeendtimeở định dạng mktimehiểu ( YYYY MM DD hh dd ss). Do đó, bạn chạy awklệnh như vậy, giả sử rằng tập lệnh Awk ở trên nằm trong một tệp thực thi filter-log-dates.awktrong thư mục làm việc hiện tại và tệp nhật ký là mylog.txt:

./filter-log-dates.awk -v starttime='2016 07 13 00 00 00' -v endtime='2016 07 20 00 00 00' mylog.txt

Lưu ý rằng thời gian kết thúc là độc quyền , tức là các bản ghi nhật ký hợp lệ phải có dấu thời gian trước thời gian kết thúc.

Nếu định dạng tem thời gian của bạn khác, bạn có thể điều chỉnh biểu thức chính quy được truyền cho matchhàm cho phù hợp với nó.


3

Bạn có thể làm điều đó trong các bước. Tìm số dòng đầu tiên khớp với mẫu bắt đầu của bạn. Tìm số dòng cuối cùng khớp với mẫu kết thúc của bạn. Sau đó trích xuất bài kiểm tra giữa hai dòng này. Điều này có thể được thực hiện như sau.

grep -n 2016-07-13 bigtextfile | head -1
grep -n 2016-07-19 bigtestfile | tail -1
# Say the first number is 1234 and the second 5678, then use...
awk 'NR>=1234 && NR<=5678' bigtestfile > rangeoftext

Điều này có thể được thực hiện tất cả trong một awklệnh nhưng các bước có thể giúp bạn làm theo dễ dàng hơn. Trong phạm vi, biến NR là số dòng hiện tại và vì không có hành động nào được chỉ định sau mẫu (NR> = 1234 && NR <= 5678), hành động mặc định là in các dòng trong phạm vi đó.

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.