Có cách nào đơn giản hơn để grep tất cả các tệp trong một thư mục không?


21

Khi tôi muốn tìm kiếm toàn bộ cây cho một số nội dung, tôi sử dụng

find . -type f -print0 | xargs -0 grep <search_string>

Có cách nào tốt hơn để làm điều này về hiệu suất hoặc ngắn gọn?


2
@Downvoter: Rất vui được cải thiện câu hỏi này nếu bạn có thể chia sẻ mối quan tâm của mình.
Dancrumb

2
nhiều phiên bản tìm kiếm có xargs tích hợp sẵn: find. -type f -exec fgrep <search_opes> {} +
đơn giản hóa

Câu trả lời:


42

Kiểm tra xem bạn grephỗ trợ -rtùy chọn (ví recurse ):

grep -r <search_string> .

1
Yup ... Tôi vừa tìm thấy stackoverflow.com/questions/16956810/ và đó cũng là câu trả lời.
Dancrumb

thêm một bình luận về --exclude-dirđể giải quyết hiệu suất và chúng tôi có một người chiến thắng!
Dancrumb

1
Chỉ cần lưu ý rằng đây không phải là di động, tuy nhiên greptrên các bản phân phối FreeBSD và Linux gần đây hỗ trợ nó. Và tại sao --exclude-dir? Bạn không yêu cầu tìm kiếm toàn bộ một cây ?
Philippos

Điểm công bằng ... --exclude-dirthực sự tiện dụng trong trường hợp sử dụng của tôi (vì các phần của cây con rất lớn, nhưng vô dụng) và tôi đã hỏi về hiệu suất ... nhưng bạn nói đúng, không cần thiết.
Dancrumb

Trong trường hợp này tôi phải thêm rằng IIRC --exclude-dirlà độc quyền cho GNU grep. (-:
Philippos

13

Một câu trả lời tối ưu phụ: Thay vì dẫn đầu ra findvào grep, bạn chỉ có thể chạy

find . -type f -exec grep 'research' {} '+'

và voila, một lệnh thay vì hai!

giải trình :

find . -type f

tìm tất cả các tập tin thường xuyên trong

-exec grep 'research'

grep 'nghiên cứu'

{}

trong tên tập tin được tìm thấy

'+'

sử dụng một lệnh cho tất cả các tên tệp, không chỉ một lần cho mỗi tên tệp.

Nb: với ';'nó sẽ có một lần cho mỗi tên tệp.

Ngoài ra, nếu bạn sử dụng điều đó để xử lý mã nguồn, bạn có thể xem xét ack, điều này được thực hiện để tìm kiếm các bit mã dễ dàng.

ack

Chỉnh sửa :

Bạn có thể mở rộng nghiên cứu đó một chút. Đầu tiên, bạn có thể sử dụng -name ''chuyển đổi findđể tìm kiếm các tệp có mẫu đặt tên cụ thể.

Ví dụ :

  • chỉ các tệp tương ứng với nhật ký: -name '*.log'

  • chỉ các tệp tương ứng với các tiêu đề c, nhưng bạn không thể gắn với chữ hoa hoặc chữ thường cho phần mở rộng tên tệp của mình: -iname *.c

Nb: like for grepack, -iswitch có nghĩa là trường hợp không nhạy cảm trong trường hợp này.

Trong trường hợp đó, grep sẽ hiển thị mà không có màu và không có số dòng.

Bạn có thể thay đổi điều đó với --colorvà các -ncông tắc (Số màu và số dòng trong tệp tương ứng).

Cuối cùng, bạn có thể có một cái gì đó như:

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

ví dụ

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
./test2/target.c:1:hello

5
acklà tuyệt vời và phiên bản nhanh hơn ackag(trình tìm kiếm bạc, geoff.greer.fm/ag )
cfeduke

1
Tôi thích cái này với bộ lọc như -name '*.log'Nó nhanh hơn.
sdkks

@cfeduke Tôi chưa thử nó, chủ yếu là vì ag không phải là một phần của kho apt mặc định trên WSL (bạn phải làm việc với những gì bạn có!)
Pierre-Antoine Guillaume

Một mẹo nhỏ là thêm / dev / null vào grep để tên tệp xuất hiện.
ChuckCottrill

Một mẹo nhỏ là chỉ tìm kiếm các thư mục và sau đó -exec grep / dev / null {} / * để lấy tất cả các tệp với một fork / exec duy nhất cho mỗi thư mục.
ChuckCottrill

12

Nếu bạn muốn lặp lại thành các thư mục con:

grep -R 'pattern' .

Các -Rtùy chọn không phải là một lựa chọn tiêu chuẩn, nhưng được hỗ trợ bởi hầu hết các chung greptriển khai.


7
Sử dụng -rthay vì -Rbỏ qua các liên kết tượng trưng khi GNU grep có liên quan
αғsнι

1
@AFSHIN Tại sao bạn không muốn theo liên kết tượng trưng?
Kusalananda

4
@Kusalananda Đệ quy? Mặc dù các greptriển khai GNU hiện tại bắt được các cuộc thu hồi, tôi nghĩ vậy. Nếu không, nó phụ thuộc vào những gì bạn có nghĩa là "cây".
Philippos

2
@Philippos IMHO, trông trẻ người dùng không phải là điều mà một công cụ như grepnên làm. Nếu người dùng có các vòng lặp liên kết tượng trưng trong cấu trúc thư mục của họ, thì đó là vấn đề của người dùng :-)
Kusalananda

3
@Kusalananda Và nếu hệ thống cung cấp vòng lặp? Không bao giờ bị lạc trong /sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...(-XI như các công cụ chăm sóc tôi (trừ khi họ cung cấp ma thuật kỳ lạ mà họ gọi là "AI"). (-;
Philippos

5

Như đã lưu ý ở trên -rhoặc -R(tùy thuộc vào xử lý symlink mong muốn) là một tùy chọn nhanh.

Tuy nhiên đôi khi -d <action>có thể hữu ích.

Điều thú vị -dlà lệnh bỏ qua, làm im lặng "grep: library_name: Is a library" khi bạn chỉ muốn quét mức hiện tại.

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  
$ 

và tất nhiên:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  
$ 

Các -d skiptùy chọn là REALLY tiện dụng bên trong kịch bản khác, do đó bạn không cần phải 2> /dev/null. :)


0

Nếu bạn đang xử lý nhiều tệp, grep sẽ chạy nhanh hơn nếu bạn cắt bớt các tệp mà nó cần tìm kiếm thay vì lấy tất cả các tệp trong các thư mục con.

Đôi khi tôi sử dụng định dạng này:

grep "primary" `find . | grep cpp$`

Tìm tất cả các tập tin trong các thư mục con của .kết thúc đó cpp. Sau đó grep những tập tin cho "chính".

Nếu bạn muốn, bạn có thể tiếp tục chuyển các kết quả đó thành các cuộc gọi grep tiếp theo:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"

1
backtics không phải là thực hành hiện đại tốt, tất cả đều lỗi thời
Christopher

1
Điều này sẽ phá vỡ nếu bạn có các tệp có ký tự đặc biệt trong tên của họ. Tôi không biết họ phải đặc biệt như thế nào để trở nên quá đặc biệt để nó hoạt động như hiện tại, nhưng những gì bạn đang làm thực sự giống như phân tích đầu ra của ls, điều này cũng rất tệ.
một CVn
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.