Làm cách nào để tìm đệ quy nội dung tệp / grep trong thư mục / thư mục con trong Emacs?


14

Tôi đang sử dụng Emacs khá lâu và bằng cách nào đó tôi vẫn không hiểu cách tốt nhất để (đệ quy) grep cho một chuỗi trong thư mục (dự án) và nhận kết quả được trình bày dưới dạng bộ đệm được điều hướng hoặc trong một số thậm chí nhiều hơn Cách hữu ích. Vui lòng làm sáng tỏ cho tôi.


Bạn đã thử sử dụng helm-projectile-greplệnh (nếu bạn đã cài đặt helm đạn) hay projectile-grepchưa?
Chakravarthy Raghunandan

Tôi không biết những gì helmhay projectile, nhưng nếu nó là một công cụ đề nghị, tôi sẽ cài đặt và tìm hiểu nó.
Boris Stitnicky

Có, projectile là một gói cung cấp một cách dễ dàng để làm những gì bạn đã đề cập trong câu hỏi với lệnh projectile-grep. Ngoài ra, tôi rất khuyến khích bạn cài đặt helmgói. Tôi không thể tưởng tượng chạy emacs mà không helmhelm-projectile. Bạn cũng có thể thú vị trong helm-aggói (cung cấp giao diện helm cho trình tìm kiếm bạc trong emacs, được cho là nhanh hơn grep hoặc ack).
Chakravarthy Raghunandan

2
Vì vậy, câu hỏi hữu ích và dễ tìm hơn đối với những người tìm kiếm trên Google và diễn đàn trong tương lai, có lẽ nên xem xét sửa đổi tiêu đề của câu hỏi để bao gồm từ đệ quy và xem xét giới hạn phạm vi - ví dụ: Cách đệ quy nội dung tệp grep trong thư mục / thư mục con . Đó chỉ là một ví dụ - nó có thể là một cái gì đó khác thay thế.
luật

1
Mặc dù các ý kiến ​​và câu trả lời cho đến nay đã đề xuất một số gói để thực hiện việc này theo nhiều cách khác nhau, tôi không thấy câu hỏi của bạn tại sao đơn giản M-x grepkhông làm những gì bạn cần. Nó cho phép bạn đưa ra một dòng lệnh tùy ý, đôi khi tôi sử dụng findở đó khi tôi cần đệ quy.
MAP

Câu trả lời:


15

Chà, vì câu hỏi ban đầu không đề cập đến rgrep, tôi sẽ tiếp tục và chỉ ra nó ở đây. Đây là tùy chọn đơn giản nhất đã được tích hợp sẵn trong Emacs và tôi thấy nó là quá đủ cho hầu hết mọi thứ.

Từ tài liệu,

Recursively grep for REGEXP in FILES in directory tree rooted at DIR.

Việc tìm kiếm được giới hạn ở tên tệp khớp với mẫu shell.

Vì vậy, ví dụ, để tìm kiếm tất cả các file python bên dưới thư mục chính của tôi cho các mục đích của some_function, tôi sẽ gọi nó với some_function, *.py, ~/như các đối số. Kết quả được hiển thị trong một bộ đệm mới.


1
Cũng có thể muốn đề cập đến find-grep-diredvì OP đã đề cập "kết quả được trình bày dưới dạng bộ đệm được điều hướng hoặc ..."
npostavs

@npostavs Tôi chưa sử dụng find-grep-diredbản thân mình, vui lòng thêm nó vào câu trả lời.
dùng2699

Tôi đã từng thử nghiệm với ack và ag, với giả định rằng tôi nên chuyển từ rgrep sang thứ gì đó bằng cách sử dụng chúng, vì chúng được cho là tốt hơn. Cuối cùng tôi đã ở lại với rgrep, vì tôi thấy không có lợi ích gì khi thay đổi! Trên dòng lệnh chắc chắn có một trường hợp được thực hiện, nhưng trong Emacs rgrepthực hiện công việc nhắm mục tiêu tìm kiếm tốt đến mức không có sự khác biệt đáng kể về tốc độ giữa chúng. (Tôi muốn nói rằng rgrep nhanh hơn một chút trong một số trường hợp, nhưng tôi không nhớ chắc chắn.)
phils

1
Lưu ý rằng next-errorprevious-errorcó thể được sử dụng để điều hướng qua tập kết quả. Tôi tìm thấy M-g M-nM-g M-pthuận tiện nhất của các ràng buộc tiêu chuẩn.
phils

find-grep-diredkhông cho tôi một bộ đệm với các liên kết tham chiếu chéo. rgrepnó cho tôi và đề nghị cuối cùng về next-error previous-errorlà tuyệt vời! Điều khó hiểu duy nhất của tôi là tất cả đầu ra thực thi lệnh lộn xộn khi bắt đầu bộ đệm.
robert

11

Tôi vui vẻ sử dụng M-x find-grep-diredtrong nhiều năm. Nó trả về kết quả dưới dạng bộ đệm được điều hướng mà bạn có thể sử dụng.


Tôi đã gặp một số khó khăn khi có được liên kết tham chiếu chéo để làm việc với điều này. Cấu hình của nó khá khó chịu ( find-ls-option) và sau tất cả những gì bạn kết thúc với một thứ khá dài dòng vì nó không hoạt động mà không có ngày trước tên tệp!
robert

5

Giải pháp 1 (giải pháp tốt nhất):

Cài đặt tư vấn ( https://github.com/abo-abo/swiper/blob/master/cdvisor.el )

Sau đó M-x counsel-git-grep.

Không cần thiết lập (git biết gốc dự án và các tệp để loại trừ). Cả hai git grepcounsellà hiệu quả.

Dự án cần được quản lý bởi git.

tư vấn yêu cầu ivy-mode.

Giải pháp 2:

Giải pháp này sử dụng grep và hoạt động trên bất kỳ dự án nào. Nó kém hơn Giải pháp 1 vì nó chậm hơn và cần thiết lập thủ công. Nó cũng dựa trên chế độ ivy.

(defvar simple-project-root "~/.emacs.d")
(defun simple-grep ()
  (interactive)
  (unless (featurep 'ivy)
    (require 'ivy))
  (let* ((default-directory (file-name-as-directory simple-project-root))
         (keyword (read-string "Keyword:")))
    (ivy-read (format "Grep at %s:" simple-project-root)
              (split-string (shell-command-to-string (format "grep -rsnI %s ." keyword)) "\n" t)
              :action (lambda (val)
                        (let* ((lst (split-string val ":"))
                               (linenum (string-to-number (cadr lst))))
                          ;; open file
                          (find-file (car lst))
                          ;; goto line if line number exists
                          (when (and linenum (> linenum 0))
                            (goto-char (point-min))
                            (forward-line (1- linenum))))))))

Bạn cần tạo .dir-locals.el để thiết lập simple-project-root, xem https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html để biết chi tiết kỹ thuật

Mã trong giải pháp 2 chỉ là một nguyên mẫu. Việc thực hiện của tôi phức tạp hơn nhiều. Xem counsel-etags-greptrong https://github.com/redguardtoo/cdvisor-etags/blob/master/cdvisor-etags.el

Tóm lược:

Đó là hai giải pháp tốt nhất mà tôi biết.

Nếu có bất kỳ giải pháp tốt hơn nào khác tồn tại, ít nhất họ cần giải quyết các vấn đề dưới đây để sẵn sàng sản xuất,

  • làm cách nào để đưa từ khóa vào grep (ví dụ: lấy từ khóa từ vùng đã chọn)

  • thoát khỏi từ khóa

  • nếu chương trình grep hiệu quả hơn tồn tại, chúng ta nên sử dụng nó (ripgrep, the_silver_searcher / ag, ... vv), hoặc nếu không thì dự phòng grep mặc định

  • cửa sổ ứng cử viên nên sử dụng toàn bộ chiều rộng màn hình và người dùng có thể lọc ứng viên tương tác (đó là lý do tại sao mọi người sử dụng cây thường xuân hoặc mũ bảo hiểm)

  • chúng ta nên hiển thị đường dẫn tương đối trong cửa sổ ứng cử viên

  • có thể sử dụng lại kết quả grepping trước đó. Vì vậy, kết quả trước đó nên được lưu lại. Bạn có thể sử dụng ivy-resumetừ ivyhoặc helm-resumetừhelm

  • Khi bạn lưu kết quả được grepping trước đó, bối cảnh của kết quả trước đó cũng sẽ được lưu lại. Ví dụ, trong mã của Giải pháp 2. default-directorylà bối cảnh. Xem https://github.com/abo-abo/swiper/issues/591 để biết thêm chi tiết.

  • Biểu thức chính quy mở rộng nên được sử dụng vì nó đơn giản hơn và đã được sử dụng bởi counsel-git-grepvà the_silver_searcher / ag.


4

Tôi muốn thêm một giải pháp khác cho giải pháp của @chen bin cũng sử dụng counsel(nhưng bạn không cần phải duy trì một dự án gitcho việc này).

Bạn cần cài đặt ag (trình tìm kiếm bạc) và counselcung cấp lệnh counsel-agtìm kiếm thư mục hiện tại cho chuỗi đã nhập.

Nếu bạn muốn tìm kiếm trong một dự án (không chỉ là thư mục làm việc hiện tại), hãy thêm nó vào .emacs: -

  (defun rag/counsel-ag-project-at-point ()
    "use counsel ag to search for the word at point in the project"
    (interactive)
    (counsel-ag (thing-at-point 'symbol) (projectile-project-root)))

Hàm này sẽ sử dụng agđể tìm kiếm đệ quy thư mục gốc của dự án.

Chỉnh sửa : chức năng trên mặc định là biểu tượng tại điểm để tìm kiếm. Nếu bạn không thích hành vi đó, thay thế (thing-at-point 'symbol)bằng nil. Và nếu bạn muốn kết quả tìm kiếm trong bộ đệm riêng, hãy nhấnC-c C-o

Edit2 : nếu bạn đã ripgrepcài đặt, bạn có thể thay thế counsel-agbằng counsel-rgchức năng trên và nó sẽ ổn thôi :)


Có thể sử projectile-project-rootdụng để tìm Rails dự án gốc?
Boris Stitnicky

Có, miễn là nó là một dự án đạn hợp lệ, nó sẽ hoạt động. Tôi nghĩ có một số gói được gọi là đường ray đạn.
Chakravarthy Raghunandan 7/12/2016

Tại sao bạn đặt tên cho chức năng rag/...?
Boris Stitnicky

Đó là một phong cách phổ biến mà mọi người thường sử dụng khi viết các chức năng của riêng họ (bạn có thể thấy nó được thực hiện bởi rất nhiều người khác nếu bạn duyệt cấu hình emacs của họ). Tất cả các chức năng tôi đã xác định bắt đầu bằng rag/tiền tố và điều đó giúp chúng dễ dàng tìm thấy trong M-x:)
Chakravarthy Raghunandan

Ic, đó là tên của bạn :-)
Boris Stitnicky

2

Dưới đây là một ví dụ về hàm grep tùy chỉnh đệ quy nội dung tệp (sử dụng biểu thức chính quy cho cụm từ tìm kiếm) trong thư mục và thư mục con của nó và hiển thị kết quả với các dòng ngữ cảnh trước và sau. Các thư viện tích hợp compile.elgrep.elcung cấp cho một số phương thức để chuyển đến vị trí trong tệp chứa kết quả tìm kiếm. Không cần phải cài đặt bất cứ thứ gì khác để ví dụ này hoạt động - tất cả những gì cần thiết là một phiên bản đầy đủ của Emacs và một máy tính có grepcài đặt tiện ích. Biến grep-programcó thể được điều chỉnh để trỏ đến một vị trí cụ thể của greptiện ích nếu mặc định là không đủ.

(defun recursive-grep ()
"Recursively grep file contents.  `i` case insensitive; `n` print line number;
`I` ignore binary files; `E` extended regular expressions; `r` recursive"
(interactive)
  (let* ((search-term (read-string "regex:  "))
         (search-path
           (directory-file-name (expand-file-name (read-directory-name "directory:  "))))
         (default-directory (file-name-as-directory search-path))
         (grep-command
           (concat
             grep-program
             " "
             "-inIEr --color=always -C2"
             " "
             search-term
             " "
             search-path)))
    (compilation-start grep-command 'grep-mode (lambda (mode) "*grep*") nil)))

Mặc dù câu hỏi không tìm cách sửa đổi đồng thời nhiều tệp được trả về dưới dạng kết quả của hàm grep ở trên, tôi thấy nó rất hữu ích khi sử dụng multiple-cursorswgrep. Nó làm cho sửa đổi nhiều tập tin trong một lần rơi một cách dễ dàng. Tuy nhiên, các thư viện cho biết sẽ cần phải được cài đặt nếu các tính năng đó được mong muốn.
luật

Lợi thế của việc sử dụng này so với nội dung là rgrepgì?
npostavs

1
@npostavs - Tôi thấy việc tích hợp rgreptốn nhiều thời gian để tùy chỉnh theo tiêu chí tìm kiếm regex ưa thích của tôi và tôi đã chọn mã hóa mọi thứ trong một chức năng tùy chỉnh (mà tôi sử dụng nhiều lần mỗi ngày). Nếu bạn muốn viết lên một câu trả lời thay thế mô tả cách tùy chỉnh rgrep, điều đó sẽ hữu ích cho những người đọc diễn đàn khác trong tương lai.
luật
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.