Emacsを使用して、まだ開いていないテキストファイルを再帰的に検索して置換する


212

この質問のフォローアップとして、これは簡単なはずのこのようなことをする方法を見つけることを試みています、それは特に私がEmacsの使用に慣れるのを防ぎ、代わりに私がすでに慣れているエディターを起動します。ここでの例は、複数のファイルを編集する際にかなり頻繁に使用します。

Ultraeditでは、Alt + sを押してからpを押して、ダイアログボックスを次のオプションで表示します:検索(複数行にまたがる正規表現の使用を含む)、置換、ファイル/タイプ、ディレクトリ、大文字と小文字を区別、単語全体とのみ一致、リスト変更されたファイルと検索サブディレクトリ。通常、最初にマウスを使用して、置換するテキストをクリックしてドラッグします。

任意の外部のユーティリティを呼び出すことなく、(WindowsのXP上)のみのEmacs自体を使用して、どのようにバー\ nbazですべてのfoo \ NBARを交換する*.c*.h、いくつかのフォルダ内のファイルとすべてのフォルダその下。Emacsはこれを行うのに最適なツールではないかもしれませんが、最小限のコマンドで簡単にそれを行うにはどうすればよいですか?

回答:


370
  1. M-x find-name-dired:ルートディレクトリとファイル名のパターンの入力を求められます。
  2. t見つかったすべてのファイルに対して「トグルマーク」を押します。
  3. 押してQ「...ファイル内の照会・交換する」ための:あなたは、クエリ/置換正規表現の入力を求められます。
  4. 次と同じように処理しquery-replace-regexpます:SPACE置換して次の一致に移動するn、一致をスキップする、など。
  5. を押しC-x sてバッファを保存します。(次にynまたは!を押すと、一度にすべてを保存できます)

10
いいえ、再帰的です。非再帰バージョンはdired-modeでは%mになります。
Chris Conway、

5
おそらく、GNU findではなく、C:\ WINDOWS \ system32 \ find.exeを呼び出しているためです。
ジャズ

6
Steen、Chris:おそらくあなたが望むものとは正確には違いますが、 'Cx s'(save-some-buffers)を使用できます。変更されたファイルごとにプロンプ​​トが表示されるので、 'y'を複数回押すだけです。
ダニエルポー2009年

48
C-x s !すべてのファイルを一度に保存します。
cYrus 2012

10
M-,検索と置換を続行するには(たとえば、ディスク上でファイルが変更された場合に「ファイルを元に戻す」プロンプトの後に)。
tfischbach 2012

37
  • M-x find-name-dired RET
    • すべてのファイルがリストに表示されるまで少し時間がかかる場合があります。M->find finished」が表示されるまで一番下()までスクロールして、すべてのファイルがロードされていることを確認します
  • t見つかったすべてのファイルの「トグルマーク」を押す
  • 押してQ「...ファイル内の照会・交換する」ための:あなたは、クエリ/置換正規表現の入力を求められます。
  • query-replace-regexp:SPACEと同様に続行するかy、置換して次の一致に移動するにはn、一致をスキップするにはnなどです。
    • タイプ!確認せずに現在のファイル内のすべての出現箇所を置き換えるN、現在のファイルの残りのすべての可能な置き換えをスキップする (Nemacs 23+のみ)
    • これ以上質問せずにすべてのファイルを置き換えるには、と入力しYます。
  • 「ibuffer」を呼び出し(C-x C-bibufferにバインドされている場合、またはM-x ibuffer RET)、開いているすべてのファイルをリストします。
  • 入力* uしてすべての未保存ファイルをマークし、入力Sしてすべてのマーク済みファイルを保存します
  • * * RETすべてのマークを外すか、タイプDしてすべてのマークされたファイルを閉じます

この回答は、この回答このサイト、および自分のメモを組み合わせたものです。Emacs 23以降を使用します。


3
ibufferC-x C-bデフォルトではバインドされていません。
phils

2
まあ、個人的に私はその人がお勧めしないバインドC-x C-bibufferそれがデフォルトのバインディングよりもそんなに良くなので、。(global-set-key (kbd "C-x C-b") 'ibuffer).emacsファイルに追加するだけです。失敗した場合M-x ibuffer RETは、上記の手順で使用してください。
phils

OK。私はemacsスタートアップキットを持っていると思います。それが私が拘束されている理由です
Frank Henard

1
ファイルbla-bla-blaは読み取り専用でアクセスされ、検索を停止します。それを回避/無視して置換を続ける方法は?ありがとう。
フェリペ

3
()と入力ibufferできるのはなぜですか?私は怒りたくはありませんが、好奇心旺盛です。PSプラス、および。C-x ssave-some-buffers!!NY
d12frost 2015

17

提供された答えは素晴らしいですが、私は少し異なるアプローチを追加したいと思いました。

これは、よりインタラクティブな方法だ、と要求するwgreprgrepiedit。両方ieditwgrep(使用MELPA又はマーマレードを介してインストールする必要がありますM-x package-list-packages

最初に実行M-x rgrepして、探している文字列を見つけます。

ファイルの種類/パターンと再帰するフォルダーを指定できます。

次に、でwgrep起動して実行する必要がありますC-s C-p

Wgrepを使用すると、rgrep結果を編集できるので、文字列の領域を照合して開始iedit-modeするように設定C-;します(端末によっては、再バインドする必要がある場合があります)

すべての出現箇所を一度に編集できます。C-x C-sコミットするwgrep。次にC-x s !、変更されたファイルを保存します。

この方法の主な利点は、iedit-mode特定の一致をオフに切り替えるために使用できることですM-;。の結果を使用して、rgrepたとえば予期しない一致があった場合などに、ファイルにジャンプすることもできます。

プロジェクト全体でソースを編集したり、シンボル(変数、関数名など)の名前を変更したりするのに非常に便利です。

ieditモードをまだ知っていない場合や使用していない場合は、非常に便利なツールです。ぜひご覧ください。


この手法は、ieditを使用しなくてもかなり強力です。これは、grepの方法(lgrep / rgrepで簡単)を知ることから、一括検索置換の方法を知ることに変わります。
NeilenMarais 2014

rgrep / wgrep / macrosの組み合わせは素晴らしいです。
ocodo 2014

2
開始するキーバインドwgrepC-c C-pbtwです。
techniao 2017

15

発射物は本当にいいです:Cc prはコマンドprojectile-replaceを実行します


13

私は通常、他のツールを使用してこのタスクを実行します。EmacsWikiの「ファイル全体の検索と置換」エントリシェルで言及されているアプローチの多くはシェルのように見えますが、Findrパッケージは非常に有望に見えます。

ソースファイルの一部を盗む:

(defun findr-query-replace (from to name dir)
  "Do `query-replace-regexp' of FROM with TO, on each file found by findr.

findr.elを使用して、拡張子がjavaおよびhxxのすべてのファイルで文字列「Collectible」を見つけようとする方法を教えてください。
swdev

@swdev:Mx findr-query-replace RET Collectible RET <置換> RET。* \。java RET <検索を開始するディレクトリ> RET
ShreevatsaR

私はこのアプローチが好きです(直接アプローチに伴うすべての切り替えを回避します)。私はいくつかの便利な関数を使用してこれを発射物(project-root-discover)と組み合わせ、ポイントで置き換えます:gist.github.com/anonymous/055a9d62f9fc824153599724b8f44d57
Att Righ

6

情報源:1

emacs proユーザーの場合:

  1. dir内のファイルを一覧表示するにはdiredを呼び出し、すべてのサブディレクトリが必要な場合はfind-diredを呼び出します。
  2. 必要なファイルをマークします。【%m】とタイプすると、正規表現でマークできます。
  3. Qと入力して、dired-do-query-replace-regexpを呼び出します。
  4. 検索正規表現を入力して文字列を置き換えます。〔☛common elisp regexパターン〕
  5. 出現ごとに、yを入力して置き換え、nを入力してスキップします。操作全体を中止するには、[Ctrl + g]を入力します。
  6. タイプ!確認せずに現在のファイル内のすべての出現箇所を置き換えるには、Nは、現在のファイルの残りのすべての可能な置き換えをスキップします。(Nはemacs 23のみ)
  7. これ以上質問せずにすべてのファイルを置換するには、Yと入力します(Emacs 23のみ)。
  8. ibufferを呼び出して、開いているすべてのファイルをリストします。保存されていないすべてのファイルをマークするには、[* u]と入力し、マークされたファイルをすべて保存するにはSと入力し、すべてを閉じるにはDと入力します。

Emacs初心者向けのステップバイステップガイド

ターゲットファイルを選択

コマンドラインインターフェイスプロンプトで「emacs」と入力してemacsを起動します。(または、グラフィックスユーザーインターフェイス環境の場合は、Emacsアイコンをダブルクリックします)

ディレクトリ内のファイルの選択

最初に、置換するファイルを選択する必要があります。グラフィカルメニューの「ファイル」▸「オープンディレクトリ」を使用してください。Emacsはディレクトリパスを尋ねてきます。ディレクトリパスを入力し、Enterキーを押します。

これで、ファイルのリストが表示されます。次に、正規表現の検索/置換を実行するファイルにマークを付ける必要があります。カーソルを目的のファイルに移動してファイルにマークを付け、mを押します。uを押してマークを解除します。(サブディレクトリを一覧表示するには、カーソルをディレクトリに移動してiを押します。サブディレクトリの内容が下部に表示されます。)すべてのファイルを正規表現でマークするには、【%m】と入力し、次に正規表現パターンを入力します。たとえば、すべてのHTMLファイルにマークを付ける場合は、【%m】、。html $の順に入力します。(マークコマンドのリストは、グラフィカルメニューの[マーク]にあります(このメニューは、diredモードのときに表示されます)。

ディレクトリとそのすべてのサブディレクトリ内のファイルを選択する

数百のサブディレクトリを含むディレクトリ内のファイルを検索/置換する場合は、これらのファイルをすべて選択する方法を次に示します。

find-diredを呼び出します。(【Alt + x】を押してコマンドを呼び出す)次に、ディレクトリ名を入力します、/ Users / mary / myfiles

注:UNIXの非グラフィカルテキストターミナルでemacsを使用していて、【Alt + x】が機能しない場合、同等のキーストロークは【Esc x】です。

Emacsは「Run find(args):」というプロンプトを表示します。すべてのHTMLファイルを置き換える必要がある場合は、-name "* html"と入力します。どのような種類のファイルでもかまいませんが、そのディレクトリの下にあるすべてのファイルだけの場合は、「-type f」を指定します。

次に、上記のようにファイルにマークを付けます。

インタラクティブな検索/置換

これで、インタラクティブな検索置換を実行する準備ができました。簡単にするために、「quick」という単語を「super」に置き換えたいとしましょう。次に、dired-do-query-replace-regexpを呼び出します。正規表現文字列と置換文字列の入力を求められます。「quick」と入力してから、「super」と入力します。

これで、emacsはパターンを使用してファイルをチェックし、一致が発生するたびに停止して表示します。これが発生すると、emacsがプロンプトを表示し、変更を行うか、変更をスキップするかを選択できます。変更するには、yと入力します。スキップするには、nと入力します。emacsで現在のファイルにそのような変更をすべて加えたい場合は、「!」と入力します。

行った変更を保存せずに操作全体をキャンセルする場合は、【Ctrl + g】と入力し、メニュー〖[ファイル]▸[Emacsの終了]を使用してemacsを終了します。

変更されたファイルの保存

さて、上記の試練を経験した後、あなたがしなければならないもう一つのステップがあり、それは変更されたファイルを保存することです。

emacsバージョン22以降を使用している場合は、ibufferを呼び出してバッファーリストモードに入り、次に[* u]と入力してすべての未保存ファイルにマークを付け、Sと入力してすべて保存します。(シフトシフトです)

emacsバージョン21を使用している場合は、これを行うことができます。list-buffersを呼び出し、カーソルを保存するファイルに移動して、sと入力します。後で保存するためにファイルにマークを付けます。マークを外すにはuと入力します。完了したら、xと入力して、保存対象としてマークされたすべてのファイルの保存を実行します。(emacsでは、開かれたファイルは「バッファ」と呼ばれます。そこで他のことは無視してください。)

上記のオプションの代わりに、save-some-buffers【Ctrl + xs】を呼び出すこともできます。次に、emacsは未保存の各ファイルを表示し、保存するかどうかを尋ねます。

注:emacsの正規表現は、PerlやPythonの正規表現とは異なりますが、類似しています。概要と一般的なパターンについては、Emacs Regexを参照してください。


2
この答えは、私が望む最も投票された答えよりも初心者にやさしいはずです。リンクの代わりに全体を置くように私をやる気にさせるための方法でありがとう。
Prashant Sharma

回答は、最初の行として、source:から始まります。コピー貼り付けの根拠は、ブログへの外部リンクが古くなり、答えが役に立たなくなることがあります。したがって、wikiメタによって提案されています。全部をコピーすることにしました。
Prashant Sharma 14年

5

diredを使用して深いディレクトリツリーを再帰するのは、このタスクでは少し遅くなります。tags-query-replaceの使用を検討するかもしれません。これは、タグテーブルを作成するために砲撃することを意味しますが、とにかく多くの場合それは便利であり、迅速です。


14,000以上のファイルがあるディレクトリで試してみました。Emacsでポップアップするのに数秒かかりました。だから絶対に遅くはない(もう)。
Berend de Boer 2014

3

オープンバッファの場合、これは私がしていることです:

(defun px-query-replace-in-open-buffers (arg1 arg2)
  "query-replace in all open files"
  (interactive "sRegexp:\nsReplace with:")
  (mapcar
   (lambda (x)
     (find-file x)
     (save-excursion
       (goto-char (point-min))
       (query-replace-regexp arg1 arg2)))
   (delq
    nil
    (mapcar
     (lambda (x)
       (buffer-file-name x))
     (buffer-list)))))

3

M-X Dired、およびtはすべてのファイルをマークし、すべてのファイルのQ置換テキストを照会します。iquery-replaceの前にコマンドを使用して、サブディレクトリを展開できます。私が追加している重要な情報は、iコマンドにプレフィックス(control-u)を指定すると、argを入力するように求められ、-R引数はすべてsubdirs を再帰的にdiredバッファーに展開します。したがって、ディレクトリ全体のすべてのファイルをクエリ検索できます。


2

別のオプションは、つらら検索を使用することです。これは、検索ヒットに対してミニバッファー入力の完了を使用する別の種類のインクリメンタル検索です。現在の入力を変更すると、一致するヒットのセットがバッファで更新され*Completions*ます。

任意の数のファイル、バッファー、またはブックマークされた場所を検索できます。これらは、ミニバッファーパターン(例:regexp)マッチングを使用して選択できます。

検索ヒットにアクセスすると、ヒット全体または現在のミニバッファー入力に一致するヒットの一部のみをオンデマンドで置き換えることができます。オンデマンドでの置換は、検索ヒットごとに順番に問い合わせが行われないことを意味します。必要なヒットに任意の順序で直接アクセスします。行う置換の数が限られている場合、このアプローチはクエリ置換よりも効果的ですy/n。徹底的なプロンプトをスキップします。

検索は、定義した検索コンテキストで行われます。ターゲットファイル内のすべてのテキストを検索することに限定されません(たとえば、コメントや特定の種類のプログラムセクションをスキップできます)。検索コンテキストの簡単な例は、のような行ですが、コンテキストは、grepパターンが一致する任意のテキストブロックにすることができます。通常、正規表現を使用して検索コンテキストを定義しますが、代わりに関数を使用できます。独自のコンテキストを定義することに加えて、さまざまな種類のコンテキスト(テキストプロパティのブロックまたはオーバーレイプロパティ、Thing-at-Pointオブジェクトなど)の定義済みのIcicles検索コマンドがあります。

アクセス/ナビゲーションを簡単にするために、検索ヒットをさまざまなソート順でソートすることもできます。


2

find-name-dired 大丈夫ですが:

  • 取得するすべてのファイルは、同じ単一の正規表現に一致します。
  • find-diredその点ではより柔軟性がありますが、一般的なルールを使用するために作成されています(たとえそれらが任意に複雑である場合でも)。そしてもちろんfind、独自の複雑な言語があります。
  • その後、名前がfind(-name)-diredバッファに収集された一部のファイルのみを操作する場合は、それらにマークを付けるか、操作しないファイルの行を削除/省略します。

代替が使用するのdired +がで(何もマークされていない場合や、すべてのファイル、)()マークされたファイルと、(b)すべてのマークされたファイルにその行為を指示するマークサブディレクトリ ...見つけ再帰的に。これにより、一般性とファイル選択の容易な制御の両方が得られます。これらの「ヒアアンドM-+ビロウ」コマンドはすべて、Diredモードのプレフィックスキーにあります。

たとえば、M-+ QQ--- query-replace と同じですが、ターゲットファイルはすべて、現在のディレクトリおよびマークされたサブディレクトリ(down、down、down ...)でマークされたすべてのファイルです。

はい、以下のようなコマンドを使用する代わりに、すべてのサブディレクトリとそのサブディレクトリを再帰的に挿入してから、などのトップレベルのコマンドを使用することもできQます。しかし、挿入されたサブディレクトリを気にしない方が便利な場合がよくあります。

それを行うには、とにかく、そのようなすべてのサブディレクトリを再帰的挿入する簡単な方法が必要です。ここでも、Dired +が役立ちます。 M-+ M-iマークされたすべてのサブディレクトリと独自のマークされたサブディレクトリを再帰的に挿入します。つまりM-i、マークされたサブディレクトリをDired +に挿入するようなものですが、サブディレクトリに対して再帰的に機能します。

(このような「ここと下」のDired +コマンドはすべて、メニュー「複数」 > 「ここと下にマーク」にあります。)

Emacs ファイルセット(任意の場所にあるファイルの名前の保存されたセット)でDired操作を実行することもできます。また、Iciclesを使用している場合は、ファイルセット内のファイルまたは他のタイプの保存済みファイルリスト用のDiredバッファーを開くことができます。

を使用して作成したものを含め、任意のDiredバッファをブックマークすることもできますfind(-name)-dired。これにより、後でそのようなセット(プロジェクトセットなど)にすばやく戻ることができます。Bookmark +を使用する場合、Diredバッファレコードにブックマークを付けます(a)そのlsスイッチ、(b)どのファイルがマークされているか、(c)どのサブディレクトリが挿入されているか、(d)どの(サブ)ディレクトリが非表示か。ブックマークに「ジャンプ」すると、そのすべてが復元されます。 Bookmark +を使用すると、Diredバッファのツリー全体をブックマークできます---ブックマークにジャンプすると、ツリー内のすべてのバッファが復元されます。


誰でも:なぜあなたがこの回答に反対票を投じたのかを説明するのは気になりますか?
ドリュー

1

まだ言及されていないもう1つの優れたツール、つまりHelmを提案したいと思います。

これは、補完、検索などを含む多くの標準的なEmacs操作の優れた代替品です。特に、helm-find-files選択した複数のファイル内でクエリの置換(正規表現を含む)を実行できます。

を開きhelm-find-files、関連ファイルにをマークして、またはをM-SPC使用して、選択したファイルでクエリ置換またはクエリ置換正規表現を実行します。F6F7


helm-find-files代わりに正規表現でマークできますM-SPCか?
Nordlöw

-2

それはEmacsではありませんが、xxdiffにはxx-renameと呼ばれるツールが付属しており、これは一度に複数の文字列(例:From To from from FROM TO)に対してそれを行い、インタラクティブなプロンプトを表示し、変更されたすべてのファイルのバックアップを保存し、短いコンテキストで行われた変更のログ。これは、大規模またはグローバルな名前変更を行うときに使用する傾向があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.