Grep có thể chỉ hiển thị các từ phù hợp với mẫu tìm kiếm không?


684

Có cách nào để tạo ra "từ" grep từ các tệp khớp với biểu thức tìm kiếm không?

Nếu tôi muốn tìm tất cả các trường hợp, giả sử "th" trong một số tệp, tôi có thể làm:

grep "th" *

nhưng đầu ra sẽ là một cái gì đó như (đậm là do tôi);

một số văn bản-file: những con mèo ngồi trên các mat  
some-other-text-file: các con cáo nâu nhanh chóng  
yet-Another-text-file: tôi hy vọng điều này giải thích cặn kẽ 

Những gì tôi muốn nó xuất ra, sử dụng cùng một tìm kiếm, là:

the
the
the
this
thoroughly

Điều này có thể sử dụng grep? Hoặc sử dụng kết hợp các công cụ khác?


2
Giải pháp Dan Midwood hoạt động hoàn hảo và xứng đáng với tín dụng.
hakish

Có cách nào người ta có thể in những từ phù hợp mà không thay đổi các dòng. Thay vào đó, chuỗi phù hợp sẽ vẫn trong cùng một dòng?
Nhà ngôn ngữ học

Câu trả lời:


954

Hãy thử grep -o

grep -oh "\w*th\w*" *

Chỉnh sửa: phù hợp với nhận xét của Phil

Từ các tài liệu :

-h, --no-filename
    Suppress the prefixing of file names on output. This is the default
    when there is only  one  file  (or only standard input) to search.
-o, --only-matching
    Print  only  the matched (non-empty) parts of a matching line,
    with each such part on a separate output line.

9
@ user181548, Tùy chọn grep -o chỉ hoạt động cho GNU grep. Vì vậy, nếu bạn không sử dụng GNU grep, nó có thể không hoạt động cho bạn.
ksinkar

5
@ABB Nó phụ thuộc vào việc bạn có muốn hiển thị tên của tệp phù hợp hay không. Tôi không chắc chắn trong điều kiện nào nó không và không hiển thị, nhưng tôi biết rằng khi tôi sử dụng grep trên một số thư mục, nó đã hiển thị đường dẫn tệp đầy đủ cho tất cả các tệp phù hợp, trong khi với -h nó chỉ hiển thị từ phù hợp mà không có bất kỳ đặc điểm kỹ thuật về nó là tập tin. Vì vậy, để phù hợp với câu hỏi ban đầu, tôi nghĩ rằng nó là cần thiết trong một số trường hợp nhất định.
LokMac

1
Tôi cần một lời giải thích cho những gì "\w*th\w*" *có nghĩa là, vì vậy tôi nghĩ rằng tôi sẽ đăng. \wlà [_ [: alnum:]], vì vậy về cơ bản, nó khớp với bất kỳ "từ" nào có chứa 'th' (vì \wkhông bao gồm khoảng trắng). * Sau phần được trích dẫn là một quả cầu chứa các tệp (nghĩa là khớp với tất cả các tệp trong thư mục này)
jeremysprofile

1
\wthường không di động đến grep -E; để có tính di động thích hợp, [[:alnum:]]thay vào đó , hãy sử dụng tên lớp ký tự POSIX (hoặc [_[:alnum:]]nếu bạn thực sự muốn gạch dưới; hoặc thử grep -Pnếu nền tảng của bạn có điều đó).
tripleee

@ABB Với đầu ra mong muốn được hiển thị bởi OP, điều -hhoàn toàn cần thiết tôi sẽ nói ..?
El Ronnoco

81

Phân phối chéo câu trả lời an toàn (bao gồm cả windows minGW?)

grep -h "[[:alpha:]]*th[[:alpha:]]*" 'filename' | tr ' ' '\n' | grep -h "[[:alpha:]]*th[[:alpha:]]*"

Nếu bạn sử dụng các phiên bản cũ hơn của grep (như 2.4.2) không bao gồm tùy chọn -o. Sử dụng ở trên. Khác sử dụng đơn giản hơn để duy trì phiên bản dưới đây.

Linux phân phối chéo câu trả lời an toàn

grep -oh "[[:alpha:]]*th[[:alpha:]]*" 'filename'

Để tóm tắt -ohkết quả, biểu thức chính quy khớp với nội dung tệp (chứ không phải tên tệp của nó), giống như cách bạn mong đợi biểu thức chính quy hoạt động trong vim / etc ... Từ nào hoặc biểu thức chính quy bạn sẽ tìm kiếm sau đó, tùy thuộc vào bạn! Miễn là bạn vẫn duy trì POSIX và không phải cú pháp perl (tham khảo bên dưới)

Thêm từ hướng dẫn cho grep

-o      Print each match, but only the match, not the entire line.
-h      Never print filename headers (i.e. filenames) with output lines.
-w      The expression is searched for as a word (as if surrounded by
         `[[:<:]]' and `[[:>:]]';

Lý do tại sao câu trả lời ban đầu không hiệu quả với tất cả mọi người

Việc sử dụng \wthay đổi từ nền tảng đến nền tảng, như một cú pháp "perl" mở rộng. Như vậy, các cài đặt grep bị giới hạn hoạt động với các lớp ký tự POSIX sử dụng [[:alpha:]]và không tương đương với perl của nó \w. Xem trang Wikipedia về biểu thức chính quy để biết thêm

Cuối cùng, câu trả lời POSIX ở trên sẽ đáng tin cậy hơn nhiều bất kể nền tảng (là bản gốc) cho grep

Đối với hỗ trợ của grep không có tùy chọn -o, grep đầu tiên xuất ra các dòng có liên quan, tr chia tách khoảng trắng thành các dòng mới, bộ lọc grep cuối cùng chỉ dành cho các dòng tương ứng.

(PS: Tôi biết hầu hết các nền tảng bây giờ, đã được vá cho \ w .... nhưng luôn có những nền tảng bị tụt lại phía sau)

Tín dụng cho cách giải quyết "-o" từ câu trả lời @AdamRosenfield


1
Điều gì về -o chỉ hoạt động trong GNU grep (như ksinkar đã đề cập trong một nhận xét về câu trả lời được chấp nhận)?
Brilliand

@Brilliand hmm, tôi gặp khó khăn khi tìm bản triển khai linux không hỗ trợ '-o', tôi có thể tìm kiếm một công việc xung quanh nếu tôi biết nên kiểm tra nền tảng nào.
PicoCreator

@pico -oTùy chọn không có trong windows grep cài đặt với gói git (minGW?): "c:\Program Files (x86)\Git\bin\grep" --version grep (GNU grep) 2.4.2
Bruce Peterson

@BrucePeterson tôi đã thêm vào câu trả lời giải pháp thay thế cho AdamRosenfield cho -o: Giúp tôi kiểm tra xem các cửa sổ git có bao gồm tr / sed và phiên bản của nó không. Vì vậy, tôi có thể kiểm tra xem cách giải quyết này có hiệu quả không
PicoCreator 04/07/2015

@pico: cho GIT: GNU sed phiên bản 4.2.1, tr (GNU textutils) 2.0
Bruce Peterson

45

Nó đơn giản hơn bạn nghĩ. Thử cái này:

egrep -wo 'th.[a-z]*' filename.txt #### (Case Sensitive)

egrep -iwo 'th.[a-z]*' filename.txt  ### (Case Insensitive)

Ở đâu,

 egrep: Grep will work with extended regular expression.
 w    : Matches only word/words instead of substring.
 o    : Display only matched pattern instead of whole line.
 i    : If u want to ignore case sensitivity.

2
Điều này dường như không thêm bất cứ điều gì qua các câu trả lời hiện có từ hơn 4 năm trước.
tripleee

3
@tripleee Tôi thấy cách tiếp cận của tôi tốt hơn và đơn giản nên tôi đã đăng bài này.
Abhinandan prasad

42

Bạn có thể dịch khoảng trắng sang dòng mới và sau đó grep, ví dụ:

cat * | tr ' ' '\n' | grep th

18
không cần mèo. tr '' '\ n' <tập tin | grep th. Chậm cho các tập tin lớn.
ghostdog74

Điều này đã không làm việc. Đầu ra vẫn chứa tên tệp và toàn bộ dòng từ tệp chứa khớp. Dù sao, một trong những giải pháp khác được cung cấp đã làm việc. Cảm ơn cho đầu vào mặc dù.
Neil Baldwin

@ ghostdog74: điểm tốt, mặc dù nếu bạn có nhiều hơn tệp, bạn sẽ cần sử dụng mèo. @Neil Baldwin: bạn có chắc bạn đã gõ nó đúng không? Khi chỉ có một tệp đầu vào (stdin trong trường hợp này), grep không in tên tệp.
Adam Rosenfield

@Adam - vâng, xin lỗi Adam, nó hoạt động với một tệp nhưng không nhiều.
Neil Baldwin

4
@ ghostdog74 nếu phần chậm là do tr, anh ta có thể làm greptrước, vì vậy trsẽ chỉ được áp dụng cho các dòng khớp:grep th filename | tr ' ' '\n' | grep th
Carcamano

37

Chỉ là awk, không cần kết hợp các công cụ.

# awk '{for(i=1;i<=NF;i++){if($i~/^th/){print $i}}}' file
the
the
the
this
thoroughly

8
@AjeetGanga tốt, nó có tên
Daerdemandt

11

lệnh grep chỉ khớp và perl

grep -o -P 'th.*? ' filename

3
Điều gì về hiển thị chỉ nhóm phù hợp?
Bishwas Mishra

Điều này không hoạt động; nó sẽ chỉ tìm thấy thbởi vì bạn đã yêu cầu sự lặp lại ngắn nhất có thể của ký tự đại diện.
tripleee

@tripleee - nó sẽ không có vấn đề đó, bởi vì có một khoảng trống ở cuối regex. Tuy nhiên, nó sẽ bỏ lỡ các từ không có khoảng trắng sau chúng, ví dụ ở cuối dòng.
Ken Williams

8

Tôi không hài lòng với cú pháp khó nhớ của awk nhưng tôi thích ý tưởng sử dụng một tiện ích để làm việc này.

Có vẻ như ack (hoặc ack-grep nếu bạn sử dụng Ubuntu) có thể thực hiện việc này một cách dễ dàng:

# ack-grep -ho "\bth.*?\b" *

the
the
the
this
thoroughly

Nếu bạn bỏ qua cờ -h bạn nhận được:

# ack-grep -o "\bth.*?\b" *

some-other-text-file
1:the

some-text-file
1:the
the

yet-another-text-file
1:this
thoroughly

Là một phần thưởng, bạn có thể sử dụng --outputcờ để thực hiện điều này cho các tìm kiếm phức tạp hơn chỉ với cú pháp dễ nhất tôi đã tìm thấy:

# echo "bug: 1, id: 5, time: 12/27/2010" > test-file
# ack-grep -ho "bug: (\d*), id: (\d*), time: (.*)" --output '$1, $2, $3' test-file

1, 5, 12/27/2010


4

Để tìm kiếm tất cả các từ bắt đầu bằng "icon-", lệnh sau hoạt động hoàn hảo. Tôi đang sử dụng Ack ở đây tương tự như grep nhưng với các tùy chọn tốt hơn và định dạng đẹp.

ack -oh --type=html "\w*icon-\w*" | sort | uniq

3

Bạn cũng có thể thử pcregrep . Ngoài ra còn có một -wtùy chọn trong grep , nhưng trong một số trường hợp, nó không hoạt động như mong đợi.

Từ Wikipedia :

cat fruitlist.txt
apple
apples
pineapple
apple-
apple-fruit
fruit-apple

grep -w apple fruitlist.txt
apple
apple-
apple-fruit
fruit-apple

3

Tôi đã có một vấn đề tương tự, tìm kiếm grep / mẫu regex và "mẫu phù hợp được tìm thấy" làm đầu ra.

Cuối cùng, tôi đã sử dụng egrep (cùng regex trên grep -e hoặc -G không cho tôi kết quả tương tự của egrep) với tùy chọn -o

vì vậy, tôi nghĩ rằng đó có thể là một cái gì đó tương tự (Tôi KHÔNG phải là một bậc thầy regex):

egrep -o "the*|this{1}|thoroughly{1}" filename

Các {1}định lượng vô dụng nên được bỏ. Hoặc nếu bạn muốn nhất quán, t{1}h{1}e{1}v.v.
tripleee

nó có thể in với cùng một dòng không?
吴毅

-1

Bạn có thể chuyển đầu ra grep của mình thành Perl như thế này:

grep "th" * | perl -n -e'while(/(\w*th\w*)/g) {print "$1\n"}'

9
Điều đó sẽ không cho kết quả chính xác. Ngoài ra, nếu sử dụng Perl, không cần sử dụng grep. làm mọi thứ trong Perl.
ghostdog74

Cảm ơn đã chỉ ra lỗi, ghostdog74. Tôi đã thay đổi nó để in tất cả các từ trên dòng, không chỉ đầu tiên.

Như tôi đã nói, grep là không cần thiết. perl -n -e'fter (/ (\ s + th \ w *) / g) {in tệp "$ 1 \ n"} '
ghostdog74

7
tùy bạn tôi chỉ minh họa một điểm. Nếu không cần thiết, đừng làm điều đó. thêm "|" sẽ chi phí cho bạn một quá trình nhiều hơn.
ghostdog74

1
Trong Perl 5.10 trở lên: perl -nE '@a = / (regrec) / ig; nói tham gia "\ n", @a '
Giáo sư Photon

-1
$ grep -w

Trích từ trang grep man:

-w: Chỉ chọn những dòng có chứa các từ trùng khớp tạo thành toàn bộ từ. Bài kiểm tra là chuỗi con phù hợp phải ở đầu dòng hoặc đứng trước ký tự cấu thành không từ.


1
Điều đó vẫn sẽ in toàn bộ dòng chứa trận đấu. Nó ràng buộc trận đấu thực tế để thekhông còn phù hợp, ví dụ như "những cái này" hoặc "tắm".
tripleee

-6

ripgrep

Dưới đây là ví dụ sử dụng ripgrep:

rg -o "(\w+)?th(\w+)?"

Nó sẽ phù hợp với tất cả các từ phù hợp th.

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.