2010-10-06 27 views
16

Tôi muốn lọc ra một vài dòng trước và sau một dòng phù hợp trong một tệp.Tìm kiếm đảo ngược grep với ngữ cảnh

này sẽ loại bỏ các dòng mà tôi không muốn:

$ grep -v "line that i don't want" 

Và điều này sẽ in 2 dòng trước và sau khi dòng Tôi không muốn:

$ grep -C 2 "line that i don't want" 

Nhưng khi tôi kết hợp chúng, nó không lọc ra 2 dòng trước và sau dòng tôi không muốn:

# does not remove 2 lines before and after the line I don't want: 
$ grep -v -C 2 "line that i don't want" 

Làm cách nào để lọc ra không chỉ dòng mà tôi không muốn, mà còn là các dòng trước và sau nó? Tôi đoán sed sẽ tốt hơn cho điều này ...

Chỉnh sửa: Tôi biết điều này có thể được thực hiện trong một vài dòng awk/Perl/Python/Ruby/etc, nhưng tôi muốn biết liệu có ngắn gọn hay không một lớp lót tôi có thể chạy từ dòng lệnh.

+1

http://superuser.com –

+0

có lý do gì không? – aaronstacy

Trả lời

4

này cung cấp cho một thử:

sed 'h;:b;$b;N;N;/PATTERN/{N;d};$b;P;D' inputfile 

Bạn có thể thay đổi số lượng N lệnh trước khi mô hình làm ảnh hưởng đến số lượng dòng để xóa.

Bạn có thể lập trình xây dựng một chuỗi chứa số N lệnh:

C=2 # corresponds to grep -C 
N=N 
for ((i = 0; i < C - 1; i++)); do N=$N";N"; done 
sed "h;:b;\$b;$N;/PATTERN/{N;d};\$b;P;D" inputfile 
+1

không, bạn có nghĩa là 'grep' chỉ không thể làm điều này ?! có lý do gì không?nó phản trực giác đối với tôi – n611x007

+0

@naxa: Khi '-C' và' -v' được sử dụng cùng nhau '-C' bao gồm các dòng bị loại trừ thay vì loại trừ các dòng bổ sung. Hãy thử điều này: 'printf '% s \ n' {1..36} | grep --color -C 2 -v '^ 2.'' và bạn sẽ thấy rằng 20, 21, 28 và 29 được bao gồm thay vì 18, 19, 30 và 31 bị loại trừ. Tùy chọn '-C' không được chỉ định bởi POSIX, nhân tiện. –

+1

Tôi hiểu rồi. cảm ơn bạn rất nhiều vì sự quan tâm của bạn và ví dụ điển hình về màu sắc! Tôi đã thử với -A và -B nhưng họ làm việc giống nhau -C. Họ cũng có vẻ là 'không posix' bây giờ mà tôi biết những gì tôi bị mất để tìm kiếm. – n611x007

1
awk 'BEGIN{n=2}{a[++i]=$0} 
/dont/{ 
    for(j=1;j<=i-(n+1);j++)print a[j]; 
    for(o=1;o<=n;o++)getline; 
    delete a} 
END{for(i in a)print a[i]} ' file 
+0

Tôi biết bạn có thể đã biết điều này vì bạn đã có nhiều XP hơn tôi, nhưng bạn có thể muốn giải thích thêm một chút so với phân đoạn mã có thể, giải quyết thực tế rằng OP đã yêu cầu một giải pháp grep, trong khi cung cấp giải pháp AWK khác rất hợp lệ và cực kỳ hữu ích của bạn. Cảm ơn! –

+0

@DermotCanniffe, lol câu trả lời được chấp nhận thậm chí còn phức tạp hơn bằng cách sử dụng sed. – ghostdog74

+0

Khá đúng. Nhiều như tôi thích sed, tôi nghĩ rằng thủ tục awk dễ dàng hơn nhiều để giải thích. :) –

2

Nếu các dòng đều duy nhất mà bạn có thể grep dòng bạn muốn loại bỏ vào một tập tin, và sau đó sử dụng file đó để loại bỏ các dòng từ bản gốc, ví dụ

grep -C 2 "line I don't want" <A.txt> B.txt 
grep -f B.txt A.txt 
0

Tôi nghĩ @ fxm27 có câu trả lời tuyệt vời, bash-y.

Tôi sẽ thêm rằng bạn có thể giải quyết cách này bằng cách sử dụng egrep nếu bạn biết trước các mẫu của các dòng tiếp theo.

command | egrep -v "words|from|lines|you|dont|want" 

Điều đó sẽ làm một "bao gồm OR", có nghĩa là một dòng phù hợp với bất kỳ trong số đó sẽ được loại trừ.

0

Tôi đã giải quyết nó bằng hai grep tuần tự. Nó có vẻ đơn giản hơn với tôi.

grep -C "match" yourfile | grep -v -f - yourfile 
Các vấn đề liên quan