Chỉ in một dòng nếu dòng tiếp theo KHÔNG chứa một kết quả khớp cụ thể


12

Tôi đang cố gắng tìm kiếm một tệp nhật ký cho các hoạt động đã đăng nhập không hoàn thành. Ví dụ: tôi đăng nhập "Hoạt động bắt đầu cho ID 1234 ..." và nếu thành công, dòng tiếp theo sẽ là "Hoạt động 1234 đã hoàn thành".

Tôi đang cố gắng để có được các dòng "Bắt đầu ..." KHÔNG được theo sau bởi các dòng "Đã hoàn thành" tương ứng của chúng.

Tệp nhật ký mẫu

Starting activity for ID 1234
ID 1234 completed successfully
Starting activity for ID 3423
ID 3423 completed successfully
Starting activity for ID 9876
ID 9876 completed successfully
Starting activity for ID 99889
ID 99889 completed successfully
Starting activity for ID 10011
ID 10011 completed successfully
Starting activity for ID 33367
Starting activity for ID 936819
ID 936819 completed successfully

Trong ví dụ này, tôi sẽ tìm đầu ra là:

Starting activity for ID 33367

... bởi vì nó không theo dòng "hoàn thành".

Tôi đã thử làm điều này với grepawk , nhưng không có nhiều thành công. Tôi cho rằng nó có thể được thực hiện với một trong những công cụ đó, nhưng tôi grepawksườn không được nâng cao.

Tìm kiếm một cách nhanh chóng và đáng tin cậy grephoặc awkmô hình để cung cấp cho kết quả tôi cần ở đây.


Tôi không nghĩ nó dễ dàng với grep + awk, nhưng bạn có thể giải thích một chút về lý do tại sao bạn làm điều đó không? Một đầu ra của tất cả các hoạt động đang chạy, ví dụ thành công hay không được hoàn thiện?
cúc

@ warl0ck, tôi đang tìm kiếm "chưa hoàn thành".
PattMauler

Câu trả lời:


10

Đây là một awkthay thế:

awk '
  /^Starting/ { I[$5] = $0                  }
  /^ID/       { delete I[$2]                }
  END         { for (key in I) print I[key] }
' infile

Đầu ra:

Starting activity for ID 33367

Các Imảng kết hợp theo dõi những gì id đã được nhìn thấy.


Điều này hoạt động thực sự tốt, vì nó thậm chí có vẻ phù hợp với các tình huống trong đó các dòng nhật ký "Bắt đầu ..." và "Đã hoàn thành ..." không liền kề / tuần tự. Cảm ơn @Thor!
PattMauler

Chào mừng bạn Điều này sẽ hoạt động hiệu quả với (gần như) kích thước đầu vào tùy ý vì nó chỉ lưu trữ ID và thời gian tra cứu là O (1).
Thor

Đẹp. Chỉ có một điều: như tôi đã học được từ @RobertL ( unix.stackexchange.com/a/243550/135943 ), bạn không cần gán giá trị để tạo thành phần mảng. Vì vậy, thay vì I[$5] = 1, bạn chỉ có thể sử dụng I[$5]. (Bạn không quan tâm đến giá trị, bạn chỉ muốn làm cho phần tử tồn tại và chỉ cần đặt tên cho nó sẽ hoàn thành điều đó.)
Wildcard

@Wildcard: Bạn đã đúng, nhưng sau khi xem xét câu hỏi của OP và grep giống như đầu ra mà anh ấy theo sau, sẽ phù hợp hơn khi nhớ toàn bộ dòng và đầu ra ở cuối.
Thor

3
sed '$!N;/\n.*completed/d;P;D' <input

Điều này sẽ xóa khỏi đầu ra tất cả các dòng đầu vào không được theo sau bởi một dòng khớp với chuỗi hoàn thành .


2

Đây là cách bạn có thể làm với GNU sed:

sed -r 'N; /([0-9]+)\n\w+\s+\1/d; P; D' infile
  • N đọc thêm một dòng vào không gian mẫu.
  • Regex khớp kiểm tra xem có tìm thấy id giống hệt nhau không, nếu vậy không gian mẫu bị xóa (d ) và chu trình được khởi động lại.
  • Nếu nó không khớp, in ra dòng đầu tiên trong không gian mẫu ( P) và xóa nó ( D).

Tôi không thể thấy bất cứ điều gì mở rộng ở đây ... vì vậy -rkhông cần thiết, phải không?
Louis Maddox

1
@lmmx: Nó là cần thiết bởi vì nếu không thì nhóm chụp cần phải được thoát, và điều tương tự cũng xảy ra với bộ +định lượng.
Thor

À Tôi đã sửa đổi nó và được cho là không cần thiết, cảm ơn vì đã làm rõ
Louis Maddox

1

nếu cài đặt của bạn hỗ trợ pcregrep, tùy chọn multiline (-M) sẽ có ích.

pcregrep -M -o '\AStarting activity for ID (\d+)\n(?!ID \1)' t.z

Bắt đầu hoạt động cho ID 33367

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.