grep để trả về dòng Nth và Mth trước và sau trận đấu


12

Tôi biết rằng với grep tôi có thể sử dụng các trường -A-Bđể kéo các dòng trước đó và tiếp theo từ một trận đấu.

Tuy nhiên, họ kéo theo tất cả các dòng giữa trận đấu dựa trên tuy nhiên nhiều dòng được chỉ định.

grep -r -i -B 5 -A 5 "match" 

Tôi chỉ muốn nhận được dòng thứ 5 trước một trận đấu và dòng thứ 5 sau trận đấu ngoài dòng phù hợp và không nhận được các dòng giữa.

Có cách nào để làm điều này với grep?


1
Bạn có thể làm điều đó bằng cách dẫn nó vào sed. Tôi mới thử nghiệm cái này và nó đã hoạt động, nhưng nó chỉ hoạt động khi có 1 trận đấu chính xác trong tệp: grep -r -i -B 5 -A 5 "match" | sed -e 1b -e '$!d'
Terrance

@Terrance cảm ơn vì lời đề nghị, như bạn đã đề cập, vì tôi đang thu thập 1000 dòng này sẽ không hoạt động.
chollida

Tôi không nghĩ grep sẽ tự hoạt động ... Tôi đang làm việc với một kịch bản bash cho bạn
Joshua Besneatte

Không vấn đề gì! Loại quan tâm để xem những gì câu trả lời bạn nhận được. =)
Terrance

Đây là trong một tập tin hoặc trong nhiều tập tin?
Joshua Besneatte

Câu trả lời:


1

Công cụ bạn muốn sử dụng được gọi là sift. Điều này về cơ bản là một grep trên steroid. Grep song song. Sift có một số lượng lớn các tùy chọn để thực hiện chính xác những gì bạn muốn - cụ thể là trả về một dòng cụ thể liên quan đến (các) trận đấu có thể / có thể không được theo sau bởi / một số văn bản.

Điều làm tôi ngạc nhiên là sift không phải là gnu chính vì nó được viết bằng ngôn ngữ cờ vây nhưng cài đặt trên Linux rất tốt. CNTT tìm kiếm song song bằng cách sử dụng tất cả số lượng lớn văn bản của cpus trong đó grep chỉ mất vài tuần để làm điều tương tự.

Trang web sàng lọc - xem ví dụ


Chào mừng bạn đến với AskUbfox, cảm ơn bạn đã trả lời. Bạn cần cung cấp một ví dụ CLI có thể giải quyết vấn đề cụ thể này thay vì cung cấp một liên kết đến trang web sàng lọc. Đây là một câu hỏi và trả lời, cảm ơn.
Bernard Wei

12

Nếu:

cat file
a
b
c
d
e
f match
g
h
i match
j
k
l
m
n
o

Sau đó:

awk '
    {line[NR] = $0} 
    /match/ {matched[NR]} 
    END {
        for (nr in matched)
            for (n=nr-5; n<=nr+5; n+=5) 
                print line[n]
    }
' file
a
f match
k
d
i match
n

+1, nhưng bạn có thể giải thích ngữ nghĩa của /match/ {matched[NR]}? Tôi chưa bao giờ thấy một mảng hoặc biến là toàn bộ một lệnh. Có phải nó đặt số lượng bản ghi hiện tại của từng dòng phù hợp vào mảng.
Joe

Đây là một điều kỳ quặc: nếu bạn tham chiếu một phần tử mảng mà không gán, khóa đó được thêm vào mảng (không có giá trị). Sau đó, phím đó hiển thị trong biểu thức key in array. Những gì tôi đang làm là ghi nhớ các số dòng nơi mẫu xuất hiện
glenn jackman

6

Về cơ bản, đây là giải pháp của Glenn, nhưng được thực hiện với Bash, Grep và sed.

grep -n match file |
    while IFS=: read nr _; do
        sed -ns "$((nr-5))p; $((nr))p; $((nr+5))p" file
    done

Lưu ý rằng số dòng nhỏ hơn 1 sẽ gây ra lỗi sed và số dòng lớn hơn số dòng trong tệp sẽ khiến nó không in được gì.

Đây chỉ là mức tối thiểu. Để làm cho nó hoạt động đệ quy và xử lý các trường hợp số dòng trên sẽ phải thực hiện một số thao tác.


6

Nó không thể được thực hiện với chỉ grep. Nếu edlà một lựa chọn:

ed -s file << 'EOF' 
g/match/-5p\
+5p\
+5p
EOF  

Kịch bản về cơ bản nói: cho mỗi trận đấu của / trận đấu /, in dòng 5 dòng trước đó, sau đó 5 dòng sau đó, sau đó 5 dòng sau đó.


5
@ubashu Bạn có nghĩ rằng OP sẽ hữu ích hơn cho OP khi đưa ra một căn hộ đơn giản "không thể thực hiện được với grep"? Tôi đang cung cấp những gì tôi tin là một giải pháp thay thế tốt để giải quyết vấn đề của OP. Từ Trung tâm trợ giúp: "Câu hỏi cụ thể là gì? Hãy chắc chắn rằng câu trả lời của bạn cung cấp điều đó - hoặc một giải pháp thay thế khả thi. Câu trả lời có thể là 'không làm điều đó', nhưng cũng nên bao gồm 'thử điều này thay thế' . "
JoL

edluôn luôn một câu trả lời, bởi vì edlà biên tập viên văn bản chuẩn.
tráng miệng

5
@ubashu Mặc dù đó không phải là grepcâu trả lời, câu trả lời của "Bạn không thể làm điều đó với X, nhưng bạn có thể làm điều đó với Y, đây là cách" vẫn là một câu trả lời hợp lệ vì bạn không chỉ trả lời câu hỏi của OP mà bạn còn cung cấp một giải pháp thay thế rằng sẽ làm việc. Đây là một loại câu trả lời hợp lệ ở đây.
Thomas Ward

5
awk '/match/{system("sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME)}' infile

Ở đây chúng tôi đang sử dụng chức năng của awk để gọi lệnh bên ngoài để in các dòng mà awk khớp với mẫu có dòng thứ 5 trước và sau trận đấu.system(command)sedmatch

Cú pháp rất dễ, bạn chỉ cần đặt chính lệnh bên ngoài vào dấu ngoặc kép cũng như các công tắc của nó và thoát khỏi những thứ bạn muốn chuyển chính xác đến lệnh, mọi thứ khác liên quan đến các awktùy chọn của chính nó phải nằm ngoài dấu ngoặc kép. Vì vậy, sed dưới đây :

"sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME

Dịch sang:

sed -n "NR-5p; NRp; NR+5p" FILENAME

NRlà số dòng khớp với mẫu matchFILENAMEtên tệp xử lý hiện tại đi qua awk.


2

sử dụng tệp văn bản mẫu của @ glenn và sử dụng perl thay vì awk:

$ perl -n0E 'say /(.*\n)(?=(?:.*\n){4}(.*match.*\n)(?:.*\n){4}(.*\n))/g' ex

sẽ cho kết quả tương tự, nhưng chạy nhanh hơn:

a
f match
k
d
i match
n

João, bạn đang xuất hiện trong hàng đánh giá LQ và @waltinator đã bỏ phiếu để xóa, vì vậy lần sau hãy tiết lộ thêm một chút ... ;-) Ngoài ra +1 để giúp bạn thoát khỏi hàng đợi LQ ... : P
Fabby

1
@JJoao Hàng đợi đánh giá chất lượng thấp. Câu trả lời của bạn có thể đã được chọn ở đó bởi vì nó là mã 90%.
wjandrea

1
@JJoao Con số 90% chỉ là cách tôi giải thích. Tôi không biết những gì heuristic thực sự được sử dụng.
wjandrea

1
Quán cà phê Menos, mais escrita! @JJoao : D ;-): D
Fabby

1
@Fabby: Sem café nada funciona: D - có lẽ nó sẽ xuất hiện trong LCQ (= hàng cà phê thấp)
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.