tìm và lặp lại tên tệp chỉ với mẫu tìm thấy


15

Tôi đã sử dụng điều này rất nhiều, cải tiến tôi cố gắng đạt được là để tránh các tên tập tin echo không khớp trong grep. Cách tốt hơn để làm điều này?

    for file in `find . -name "*.py"`; do echo $file; grep something $file; done

Câu trả lời:


23
find . -name '*.py' -exec grep something {} \; -print

sẽ in tên tập tin sau khi các dòng phù hợp.

find . -name '*.py' -exec grep something /dev/null {} +

sẽ in tên tệp ở trước mỗi dòng trùng khớp (chúng tôi thêm /dev/nullvào trường hợp chỉ có một tệp phù hợp là grepkhông in tên tệp nếu nó chỉ truyền một tệp để xem. Việc triển khai GNU grepcó một -Htùy chọn cho điều đó như một sự thay thế).

find . -name '*.py' -exec grep -l something {} +

sẽ chỉ in tên tệp của các tệp có ít nhất một dòng khớp.

Để in tên tệp trước các dòng trùng khớp, bạn có thể sử dụng awk thay thế:

find . -name '*.py' -exec awk '
  FNR == 1 {filename_printed = 0}
  /something/ {
    if (!filename_printed) {
      print FILENAME
      filename_printed = 1
    }
    print
  }' {} +

Hoặc gọi grephai lần cho mỗi tệp - mặc dù điều đó sẽ kém hiệu quả hơn vì nó sẽ chạy ít nhất một greplệnh và tối đa hai cho mỗi tệp (và đọc nội dung của tệp hai lần):

find . -name '*.py' -exec grep -l something {} \; \
                    -exec grep something {} \;

Trong mọi trường hợp, bạn không muốn lặp lại kết quả đầu ra findnhư thếnhớ trích dẫn các biến của mình .

Nếu bạn muốn sử dụng vòng lặp shell, với các công cụ GNU:

find . -name '*.py' -exec grep -l --null something {} + |
   xargs -r0 sh -c '
     for file do
       printf "%s\n" "$file"
       grep something < "$file"
     done' sh

(cũng hoạt động trên FreeBSD và các công cụ phái sinh).


6

Nếu bạn đang sử dụng GNU grep, bạn có thể sử dụng tùy chọn -rhoặc --recursivetùy chọn này để thực hiện tìm kiếm đơn giản này cho bạn:

grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match

Bạn chỉ cần findnếu bạn cần các vị từ nâng cao hơn.


1
Tùy thuộc vào phiên bản GNU grep, grepcó thể hoặc không thể nhìn vào bên trong các liên kết tượng trưng hoặc liên kết ngang qua các thư mục. Bạn cũng có thể tìm thấy một số biến thể trong việc xử lý các loại tệp không thường xuyên khác.
Stéphane Chazelas

5

Bạn có thể yêu cầu grep đưa tên tệp vào đầu ra. Vì vậy, nếu có một trận đấu, nó sẽ được hiển thị trên bảng điều khiển; nếu không có kết quả khớp trong một tệp, sẽ không có dòng nào được in cho tệp đó.

find . -name "*.py" | xargs grep -n -H something

Từ man grep:

-H       Always print filename headers with output lines
-n, --line-number
         Each output line is preceded by its relative line number in the file, starting at line 1.  The line number counter is reset for each file processed.
         This option is ignored if -c, -L, -l, or -q is specified.

Nếu các tệp của bạn có thể có tên có khoảng trắng trong đó, bạn phải chuyển đổi đường ống để sử dụng Ký tự NUL làm phân cách. Lệnh đầy đủ bây giờ sẽ trông như thế này:

find . -name "*.py" -print0 | xargs -0 grep -n -H something

1

Bạn có thể thử một cái gì đó như:

find . -name "*.py:" -exec grep -l {} \;

Lệnh exec grep này cho mọi tệp, được phát hiện bởi lệnh find và tính năng lệnh find tiêu chuẩn của nó


1

Sử dụng -lđối số.

for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done

Một cách sử dụng hữu ích hơn sẽ là:

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done

1

Có những greplựa chọn thay thế theo mặc định xuất kết quả của chúng theo định dạng bạn muốn. Hai cái phổ biến nhất mà tôi biết là ag(hay còn gọi là "người tìm kiếm bạc") và ack. agđược quảng cáo là một thay thế nhanh hơn để ack.

$ ag '^\w+\s*\w+\(' ~/build/i3/src
build/i3/src/display_version.c
58:void display_running_version(void) {

build/i3/src/load_layout.c
42:static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
518:json_content_t json_determine_content(const char *filename) {
575:void tree_append_json(Con *con, const char *filename, char **errormsg) {

build/i3/src/x.c
64:CIRCLEQ_HEAD(state_head, con_state) state_head =
67:CIRCLEQ_HEAD(old_state_head, con_state) old_state_head =
70:TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head =
97:void x_con_init(Con *con, uint16_t depth) {
...

Tôi không thể chỉ cho bạn ở đây, nhưng đầu ra được tô màu gọn gàng. Tôi nhận được tên tập tin trong một màu xanh ô liu, số dòng màu vàng vàng và mảnh phù hợp trong mỗi dòng có màu đỏ máu. Các màu sắc có thể tùy chỉnh mặc dù.

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.