Emacsのディレクトリ/サブディレクトリ内のファイルの内容を再帰的に検索/ grepする方法は?


14

私はかなり長い間Emacsを使用していますが、(プロジェクト)ディレクトリ内の文字列を(再帰的に)grepする最良の方法が何であるかまだ理解しておらず、結果をdiredバッファまたはさらにそれ以上で表示します便利な方法。教えてください。


helm-projectile-grepコマンド(ヘルム発射体がインストールされている場合)を使用して試しましたかprojectile-grep
チャクラヴァルシーラグナナンダン

私は何を知らないhelmprojectileであるが、それは推奨ツールであるならば、私はそれをインストールして学びます。
ボリススティトニッキー

はい、発射物は、コマンドで質問で言及したことを簡単に実行できるパッケージですprojectile-grep。また、helmパッケージをインストールすることを強くお勧めします。helmおよびなしでemacsを実行することは想像できませんhelm-projectilehelm-agパッケージ(emacsのシルバーサーチャーにヘルムインターフェイスを提供し、grepやackよりも高速であると思われる)にも興味があるかもしれません。
チャクラヴァルシーラグナナンダン

2
質問が将来のGoogleやフォーラムの検索者にとってより便利で見つけやすいように、おそらく質問のタイトルを変更して単語を再帰的に含めることを検討し、範囲を制限することを検討してください。たとえば、ディレクトリ内のファイルの内容を再帰的にgrepする方法/サブディレクトリ。これは単なる例です。代わりに他の何かを使用できます。
法律家

1
これまでのコメントと回答は、これをさまざまな派手な方法で行うための多くのパッケージを示唆していますが、あなたの質問から、単純なM-x grepものがあなたが必要とすることをしない理由はわかりません。任意のコマンドラインを指定してみましょうfind。再帰が必要なときに時々使用します。
MAP

回答:


15

元の質問では言及していないので、rgrep先に進み、ここで指摘します。これはすでにEmacsに組み込まれている最も単純なオプションであり、ほとんどの場合には十分すぎることがわかりました。

ドキュメントから、

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

検索は、シェルパターンFILESに一致するファイル名に制限されます。

したがって、たとえば、ホームディレクトリの下にあるすべてのpythonファイルを検索して、の使用についてはsome_function、引数としてsome_function*.pyで呼び出し~/ます。結果は新しいバッファーに表示されます。


1
find-grep-diredOPが「結果をdiredバッファーまたは...として提示した」と述べたため、同様に言及したいかもしれ
ません-npostavs

@npostavs私はfind-grep-dired自分自身を使ったことがないので、気軽に答えに加えてください。
user2699

私はかつてrgrepからrgrepを使用するものに切り替えるべきであると仮定して、ackやagのようなものを試しました。最終的に私はrgrepにとどまりました。変更することには何のメリットもなかったからです。コマンドラインには確かにケースがありますが、Emacs rgrepでは検索をターゲットにするのに非常に良い仕事をしているので、それらの間に著しい速度差はありませんでした。(rgrepは一部のケースでわずかに高速であったと言いたいのですが、確かに覚えていません。)
phils

1
next-errorprevious-errorは、結果セットをナビゲートするために使用できることに注意してください。私は見つけるM-g M-nM-g M-p標準バインディングの最も便利。
-phils

find-grep-dired相互参照リンクを備えたバッファを提供しません。rgrep私のためにそれをし、その最後の提案next-error previous-errorは素晴らしいです!私の唯一の問題は、バッファの先頭にあるすべての乱雑なコマンド実行出力です。
ロバート

11

M-x find-grep-dired年も喜んで使っています。結果をdiredバッファーとして返します。これは使用できます。


相互参照リンクをこれで動作させるのに苦労しました。構成は非常に厄介です(find-ls-option)、結局、ファイル名の前に日付がないと機能しないため、非常に冗長なものになります!
ロバート

5

ソリューション1(最適なソリューション):

弁護士をインストールする(https://github.com/abo-abo/swiper/blob/master/counsel.el

その後M-x counsel-git-grep

セットアップは不要です(gitはプロジェクトのルートと除外するファイルを認識しています)。両方git grepcounsel効率的です。

プロジェクトはgitで管理する必要があります。

弁護士はアイビーモードが必要です。

解決策2:

このソリューションはgrepを使用し、任意のプロジェクトで動作します。速度が遅く、手動セットアップが必要なため、ソリューション1より劣ります。また、アイビーモードに基づいています。

(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))))))))

セットアップするには.dir-locals.elを作成する必要があります技術的な詳細simple-project-rootについてはhttps://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.htmlを参照してください

ソリューション2のコードは単なるプロトタイプです。私の実際の実装ははるかに複雑です。https://github.com/redguardtoo/counsel-etags/blob/master/counsel-etags.elを参照counsel-etags-grepしてください

概要:

これらは、私が知っている最高の2つのソリューションです。

他の優れたソリューションが存在する場合、少なくとも以下の問題を解決して生産準備を整える必要があります。

  • grepにキーワードを取得する方法(たとえば、選択した地域からキーワードを取得する)

  • キーワードをエスケープする

  • より効率的なgrepプログラムが存在する場合は、それを使用する必要があります(ripgrep、the_silver_searcher / ag、...など)、またはデフォルトのgrepをフォールバックします

  • 候補ウィンドウは画面の全幅を使用する必要があり、ユーザーは候補をインタラクティブにフィルター処理できます(そのため、人々はivyまたはhelmを使用します)

  • 候補ウィンドウに相対パスを表示する必要があります

  • 以前のgrepさ​​れた結果を再利用できます。したがって、以前の結果を保存する必要があります。ivy-resumefrom ivyまたはhelm-resumefrom を使用できますhelm

  • 以前のgrepさ​​れた結果を保存すると、以前の結果のコンテキストも保存されます。たとえば、ソリューション2のコードにdefault-directoryはコンテキストがあります。詳細については、https://github.com/abo-abo/swiper/issues/591を参照してください。

  • 拡張された正規表現は、より単純でcounsel-git-grepあり、the_silver_searcher / ag によって既に使用されているため、使用する必要があります。


4

@chen binのソリューションにも使用する別のソリューションを追加したいと思いますcounsel(ただしgit、このためにプロジェクトを管理する必要はありません)。

ag(シルバーサーチャー)をインストールする必要があり、入力した文字列を現在のディレクトリで検索するcounselコマンドcounsel-agを提供します。

(現在の作業ディレクトリだけでなく)プロジェクト内を検索する場合は、これをあなたの.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)))

この関数はag、プロジェクトのルートディレクトリを再帰的に検索するために使用します。

編集:上記の関数は、デフォルトで検索ポイントのシンボルになります。その動作が気に入らない場合は、に置き換え(thing-at-point 'symbol)てくださいnil。そして、検索結果を自分のバッファーで押したい場合はC-c C-o

EDIT2:あなたがした場合ripgrepにインストール、あなたは置き換えることができcounsel-agcounsel-rg上記の関数で、それだけで罰金としてよ:)


あるprojectile-project-rootRailsのプロジェクトのルートを見つけるために使用できますか?
ボリススティトニッキー16

はい、有効な発射物プロジェクトである限り機能します。発射体レールと呼ばれるいくつかのパッケージがあったと思います。
チャクラヴァルシーラグナナンダン

なぜ関数に名前を付けたのrag/...ですか?
ボリススティトニッキー16

これは、人々が自分の関数を書くときによく使用する一般的なスタイルです(emacs configを参照すると、他の多くの人によって実行されていることがわかります)。私が定義したすべての関数はrag/接頭辞で始まり、M-x
それで

Ic、それはあなたの名前です:-)
ボリススティトニッキー

2

次に、ディレクトリとそのサブディレクトリ内のファイルの内容を再帰的に(検索用語に正規表現を使用して)取得し、前後のコンテキスト行で結果を表示するカスタムgrep関数の例を示します。ビルトインcompile.elおよびgrep.elライブラリは、検索結果を含むファイル内の場所にジャンプするいくつかの方法を提供します。この例が機能するために他のものをインストールする必要はありません。必要なのは、Emacsのフルバージョンとgrepユーティリティがインストールされているコンピューターだけです。デフォルトでは不十分な場合、ユーティリティのgrep-program特定の場所を指すように変数を調整できますgrep

(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)))

この質問は、上記のgrep関数によって結果として返される複数のファイルを同時に変更する方法を探しているわけではありませんが、multiple-cursorsand を使用すると非常に役立ちますwgrep。複数のファイルを1回で簡単に変更できます。ただし、これらの機能が必要な場合は、これらのライブラリをインストールする必要があります。
法律家

組み込みよりもこれを使用する利点は何rgrepですか?
-npostavs

1
@npostavs-ビルトインはrgrep、好みの正規表現検索条件にカスタマイズするのに時間がかかることがわかり、すべてをカスタム関数(毎日数回使用する)でハードコーディングすることを選択しました。をカスタマイズする方法を説明する別の回答を書きたい場合rgrepは、将来他のフォーラムリーダーに役立つでしょう。
法律家
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.