Vim Search ersetzt alle Dateien im aktuellen (Projekt-) Ordner

36

Eine der offenen Fragen, die ich zu Vim habe, ist, ob es eine Möglichkeit gibt, im aktuellen Projekt eine Suche / Ersetzung durchzuführen.

Angenommen, ich möchte meine Projektdateien nach einem Methodennamen durchsuchen und alle Instanzen dieses Methodenaufrufs umbenennen.

So kann ich mit Sublime fortfahren.

Bildbeschreibung hier eingeben

Wie würden Sie dies in Vim (möglicherweise MacVim) tun, ohne sich auf andere Programme wie ackoder zu verlassen sed?

Simone Carletti
quelle

Antworten:

35

Hierfür gibt es verschiedene Möglichkeiten.

Im aktuellen Verzeichnis

Wenn Sie das Suchen / Ersetzen in einem Projektbaum ausführen möchten, können Sie die Argumentliste von Vim verwenden .

Öffnen Sie einfach Vim und :argsfüllen Sie die Argumentliste mit dem Befehl aus. Sie können mehrere Dateinamen oder sogar Globs übergeben.

:args **/*.rbSucht beispielsweise rekursiv im aktuellen Verzeichnis nach Ruby-Dateien. Beachten Sie, dass dies auch wie das Öffnen von Vim mit ist vim **/*.rb. Sie können sogar den findBefehl der Shell verwenden , um eine Liste aller Dateien im aktuellen Verzeichnis abzurufen, indem Sie Folgendes ausführen:

:args `find . -type f`

Sie können die aktuelle Argumentliste anzeigen, :argsindem Sie sie selbst ausführen . Wenn Sie Dateien zur Liste hinzufügen oder daraus löschen möchten, können Sie :argaddden :argdeleteBefehl oder verwenden.

Wenn Sie mit der Liste zufrieden sind, können Sie jetzt den leistungsstarken :argdoBefehl von Vim verwenden, der für jede Datei in der Argumentliste einen Befehl ausführt::argdo %s/search/replace/g

Hier sind einige Tipps für die Suche (basierend auf einigen Kommentaren):

  1. Verwenden Sie eine Wortgrenze, wenn Sie nach "foo", aber nicht nach "foo_bar" suchen möchten. Verwenden Sie die \<und \>-Konstrukte um das Suchmuster wie folgt::argdo %s/\<search\>/foobar/g
  2. Verwenden Sie ein /cSuchflag, wenn Vim vor dem Ersetzen eines Suchbegriffs eine Bestätigung anfordern soll.
  3. Verwenden Sie ein /eSuchflag, wenn Sie die Fehler "Muster nicht gefunden" überspringen möchten.
  4. Sie können auch die Datei speichern nach der Durchführung der Suche wählen: :argdo %s/search/replace/g | update. Hier :updatewird verwendet, weil die Datei nur gespeichert wird, wenn sie geändert wurde.

Puffer öffnen

Wenn Sie bereits Puffer geöffnet haben, für die Sie suchen / ersetzen möchten, können Sie verwenden :bufdo, dass für jede Datei in Ihrer Pufferliste ein Befehl ausgeführt wird ( :ls).

Der Befehl ist sehr ähnlich zu :argdo: :bufdo %s/search/replace/g

Ähnlich wie :argdound :bufdogibt es :windound :tabdowirkt sich auf Fenster bzw. Registerkarten aus. Sie werden seltener verwendet, sind aber dennoch nützlich zu wissen.

akshay
quelle
4
Es könnte wahrscheinlich eine gute Idee sein, das /cFlag zur Bestätigung von Substitutionen zu verwenden.
Romainl
3
Ich würde auch empfehlen Wortgrenzen mit \<und \>um die searchTeilwort - Ersatz zu vermeiden.
tommcdo
1
Ein weiterer Kommentar ist, dass das Arbeitsverzeichnis von vim standardmäßig das Verzeichnis ist, in dem Sie vim gestartet haben, nicht das Verzeichnis der aktuellen Datei. Sie können das Arbeitsverzeichnis mit auf die aktuelle Datei setzen :cd %:p:h. Weitere Optionen für das Arbeitsverzeichnis finden Sie in vim.wikia.com/wiki/Set_working_directory_to_the_current_file .
Studgeek
28

Nehmen wir an, wir haben eine einfache Projektstruktur wie diese:

Bildbeschreibung hier eingeben

gruss.txt sieht aus wie

Bildbeschreibung hier eingeben

und info / age.txt sieht aus wie

Bildbeschreibung hier eingeben

Angenommen, wir möchten alle Vorkommen von Sam durch Bob ersetzen. Folgendes würden wir tun:

  1. Arbeitsverzeichnis festlegen

    Stellen Sie sicher, dass das aktuelle Arbeitsverzeichnis von Vim das Stammverzeichnis des Projekts ist (hier erfahren Sie nicht, wie Sie dies tun).

  2. Dateien suchen, die 'Sam' enthalten

    Verwenden Sie den Befehl vimgrep von Vim, um nach allen Vorkommen von Sam im Projekt zu suchen (Hinweis: Die **/*Suche in allen Dateien erfolgt rekursiv).

    :vimgrep /Sam/gj **/*
    

    Dadurch wird die Quickfix-Liste mit allen Instanzen von Sam gefüllt. Wenn Sie die Quickfix-Liste anzeigen möchten, können Sie den Befehl Vim verwenden:copen Bildbeschreibung hier eingeben

  3. Ersetzen Sie in allen Dateien, die "Sam" enthalten

    Jetzt wollen wir Vims Ersatzbefehl in jeder Datei in der Quickfix-Liste ausführen. Wir können dies mit dem :cfdo {cmd}Befehl tun, der in jeder Datei in der Quickfix-Liste {cmd} ausführt. Das spezifische {cmd}, das wir verwenden möchten, ist substituteoder skurz. Die vollständige Zeile würde folgendermaßen aussehen:

    :cfdo %s/Sam/Bob/g
    

    Sie können das c-Flag hinzufügen, um alle Ersetzungen zu bestätigen, wenn Sie möchten:

    :cfdo %s/Sam/Bob/gc
    
  4. Speichern Sie alle Dateien

    :cfdo update
    
Niko Bellic
quelle
2
Ich mag das mehr. Es ist einfach und funktioniert mit Ack (oder jedem Plugin, das das QuickFix-Fenster ausfüllt).
Zuhaib
1
Dies ist eine großartige Antwort
Peoplee
2
Wurde "seit der letzten Änderung nicht mehr geschrieben", cfdo %s/Sam/Bob/g | updatewas für mich
behoben wurde
@hakunin Ich würde empfehlen, die hiddenOption mit festzulegen, :set hiddenwenn Sie dies noch nicht getan haben.
Niko Bellic
3

Obwohl dies keine VIM-Lösung ist, ist es für Sie unter Umständen einfacher, eine CLI-Lösung zu verwenden, wenn Sie VI / VIM verwenden. Um alle Dateien im aktuellen Verzeichnis zu ändern, verwenden perlSie die folgenden Einstellungen:

$ perl -pi -e 's/foo/bar/g' *

Wenn Sie es auch in Unterverzeichnissen tun müssen, paare ich normalerweise perlmit find:

$ find . -name '*' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'

Das Schöne daran ist, dass Sie die Liste problemlos auf bestimmte Dateitypen verfeinern können. So beschränken Sie sich beispielsweise auf Python-Dateien:

$ perl -pi -e 's/foo/bar/g' *.py
$ find . -name '*.py' -print0 | xargs -0 perl -pi -e 's/foo/bar/g'
dotancohen
quelle
1

Um eine Phrase durch eine andere zu ersetzen, können Sie den Vim Ex-Modus verwenden.

Zum Beispiel ( exist ein Alias ​​für vim -E):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa *.*

Rekursiv in bash / zsh (mit globstarset, zB shopt -s globstar):

$ ex -s +'bufdo!%s/foo/bar/g' -cxa **/*.*
$ ex -s +'n **/*.*' +'bufdo!%s/foo/bar/g' -cxa

Rekursiv (Verwenden findund Ignorieren von versteckten Dateien wie .gitDateien):

$ find . -type f -not -path '*/\.*' -exec ex -s +'bufdo!%s/foo/bar/g' -cxa {} "+"

Hinweis: Der :bufdoBefehl ist nicht POSIX .

Hinweis: Mit der Syntax -not -path '*/\.*'werden versteckte Dateien (z. B. .git) ignoriert .

Kenorb
quelle
note bufdo ist nicht POSIX pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html
Steven Penny
0

Hier ist der Shell-Befehl using findund exeditor (ohne using:bufdo ):

find . -name '*.rb' -exec ex +'%s/foo/bar/ge' -V1 -scwq! {} ';'

Dies wird bearbeiten in-legen Sie alle *.rbDateien im aktuellen Ordner (rekursiv) und ersetzen foomit bar.

Kenorb
quelle