Làm thế nào để grep -v và cũng loại trừ dòng tiếp theo sau trận đấu?


14

Làm cách nào để lọc ra 2 dòng cho mỗi dòng khớp với biểu thức grep regex?
đây là bài kiểm tra tối thiểu của tôi:

SomeTestAAAA
EndTest
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestAABC
EndTest
SomeTestACDF
EndTest

Và rõ ràng tôi đã thử ví dụ như grep -vA 1 SomeTestAAkhông hoạt động.

đầu ra mong muốn là:

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

grep -v 'Một số văn bản' | uniq?
DarkHeart

Câu trả lời:


14

Bạn có thể sử dụng grepvới -P(PCRE):

grep -P -A 1 'SomeTest(?!AA)' file.txt

(?!AA)là mô hình nhìn tiêu cực chiều rộng bằng không đảm bảo rằng không có AAsau SomeTest.

Kiểm tra :

$ grep -P -A 1 'SomeTest(?!AA)' file.txt 
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

các nhân vật thoát cho dấu chấm là gì? thích một số.Test.AA?
Behrooz

1
@Behrooz thoát chấm bởi \.rất grep -P -A 1 'SomeTest\.(?!AA)' file.txthaygrep -P -A 1 'SomeTest(?!\.AA)' file.txt
heemayl

Điều này hoạt động trong trường hợp cụ thể này bởi vì trong các dòng mẫu của OP có các cặp SomeTest*\nEndTestnên bạn thực sự grepping tất cả các dòng khớp SomeTest*nhưng không SomeTestAA+ một dòng ngữ cảnh sau trận đấu. Thêm một số dòng nữa vào đầu vào (ví dụ: thêm một dòng foobarsau mỗi EndTestdòng), sau đó thử lại.
don_crissti

1
@don_crissti đó là sự thật, tôi đã làm việc xung quanh đó.
Behrooz

@Behrooz - quan tâm chia sẻ với chúng tôi cách bạn làm việc xung quanh vấn đề đó và có thể trả lời nhận xét của tôi dưới câu hỏi của bạn?
don_crissti

4

Đây là một sedgiải pháp ( -nkhông có tự động in) hoạt động với đầu vào tùy ý:

sed -n '/SomeTestAA/!p          # if line doesn't match, print it
: m                             # label m
//{                             # if line matches
$!{                             # and if it's not the last line
n                               # empty pattern space and read in the next line
b m                             # branch to label m (so n is repeated until a
}                               # line that's read in no longer matches) but
}                               # nothing is printed
' infile

vì vậy với một đầu vào như

SomeTestAAXX
SomeTestAAYY
+ one line
SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestAABC
+ another line
SomeTestTHREE
EndTest
SomeTestAA
+ yet another line

đang chạy

sed -n -e '/SomeTestAA/!p;: m' -e '//{' -e '$!{' -e 'n;b m' -e '}' -e'}' infile

đầu ra

SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestTHREE
EndTest

nghĩa là, nó loại bỏ chính xác các dòng grep -A1 SomeTestAA infilesẽ chọn:

SomeTestAAXX
SomeTestAAYY
+ one line
--
SomeTestAABC
+ another line
--
SomeTestAA
+ yet another line

Hấp dẫn. Tôi đã không nhận ra rằng //phù hợp /SomeTestAA/. Tôi nghĩ, trong trường hợp này, nó sẽ khớp với biểu thức phủ định : /SomeTestAA/!. (+1)
Peter.O 30/08/2015

@ Peter.O - cảm ơn! Không, theo thông số kỹ thuật, một RE trống phải luôn khớp với RE cuối cùng được sử dụng trong lệnh cuối cùng; những !không phải là một phần của RE , đó là một sedđiều.
don_crissti

3

Bạn có thể gặp may mắn hơn với thứ gì đó xem các vùng nhiều dòng dưới dạng các bản ghi đơn lẻ. Có một sgrepcái mà tôi đã không sử dụng nhiều.

Ngoài ra còn có awk, nơi bạn có thể đặt trình phân tách bản ghi đầu vào và phân tách bản ghi đầu ra, thành bất cứ thứ gì bạn thích.

pat="^SomeTestAA"
awk  'BEGIN{ RS=ORS="\nEndTest\n"} !/'"$pat/" foo

Hầu hết các chương trình awk là trích dẫn đơn, nhưng tôi thay đổi thành dấu ngoặc kép ở cuối để $patbiến shell có thể được mở rộng.


awk -vpat="^SomeTestAA" -vRS="\nEndTest\n" 'BEGIN{ ORS=RS } $0 !~ pat' file
Peter.O

3

Một lựa chọn là sử dụng pERL compatible regular expression grep:

pcregrep -Mv 'SomeTestAA.*\n' file

Tùy chọn -Mcho phép mô hình khớp với nhiều hơn một dòng.


1
@don_crissti Cả hai dòng sẽ bị xóa. Thông số kỹ thuật của OP không bao gồm trường hợp này.
jimmij

Rõ ràng là mẫu và câu hỏi của OP không bao gồm các trường hợp như vậy, tôi chỉ tò mò muốn biết cách thức hoạt động của nó (tôi không quen với pcre) bởi vì với một số dòng liên tiếp trùng khớp, điều này hoạt động (nó loại bỏ dòng ngữ cảnh cũng vậy) và với số dòng chẵn liên tiếp khớp nhau, nó không thành công (nó không xóa dòng ngữ cảnh sau).
don_crissti

Cho rằng (GNU) grepđã hỗ trợ PCRE (thông qua -Ptùy chọn), lợi thế của việc sử dụng là pcregrepgì?
thân

@arielf grepkhông hỗ trợ -Mtùy chọn.
jimmij

1

Sử dụng tiêu chuẩn sed:

$ sed '/SomeTestAA/{ N; d; }' file
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

Các sedkịch bản phân tích các dòng tập tin đầu vào của dòng, và khi một dòng phù hợp với mô hình SomeTestAA, hai sedlệnh chỉnh sửa Ndđược thực thi. Các Nlệnh gắn thêm dòng tiếp theo của đầu vào cho các không gian mẫu (bộ đệm mà sedcó thể sửa đổi), và dxóa các không gian mẫu và bắt đầu chu kỳ tiếp theo.


0

Bạn có thể sử dụng lệnh sedcủa GNU dđể xóa một dòng và tiền tố nó /pat/,+Nđể chọn các dòng khớp với mẫu và N dòng tiếp theo . Trong trường hợp của bạn, N = 1 vì bạn chỉ muốn xóa một dòng tiếp theo sau một dòng phù hợp:

sed -e '/SomeTestAAAA/,+1d'

0

Đã thử với lệnh sed bên dưới và nó hoạt động tốt

chỉ huy

sed  '/SomeTestAA/,+1d' filename

đầu ra

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest
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.