La recherche Vim remplace tous les fichiers du dossier (projet) actuel

37

L'une des questions que je me pose à propos de Vim est de savoir s'il existe un moyen d'effectuer une recherche / un remplacement dans le projet en cours (indiquez avec moi si j'utilise cette notion héritée d'autres éditeurs).

Par exemple, supposons que je souhaite rechercher un nom de méthode dans mes fichiers de projet et renommez toutes les instances de cet appel de méthode.

Voici comment je peux procéder avec Sublime.

entrez la description de l'image ici

Comment feriez-vous cela dans Vim (éventuellement MacVim) sans utiliser d'autres programmes tels que ackou sed?

Simone Carletti
la source

Réponses:

35

Il y a plusieurs moyens de le faire.

Dans le répertoire actuel

Si vous souhaitez effectuer la recherche / remplacement dans une arborescence de projet, vous pouvez utiliser la liste d'arguments de Vim .

Ouvrez simplement Vim puis utilisez la :argscommande pour remplir la liste des arguments. Vous pouvez transmettre plusieurs noms de fichiers ou même des globs.

Par exemple, :args **/*.rbcherchera de manière récursive dans le répertoire actuel les fichiers ruby. Notez que c'est aussi comme ouvrir Vim avec vim **/*.rb. Vous pouvez même utiliser la findcommande du shell pour obtenir une liste de tous les fichiers du répertoire actuel en exécutant:

:args `find . -type f`

Vous pouvez afficher la liste des arguments en cours :argsen s'exécutant tout seul. Si vous souhaitez ajouter ou supprimer des fichiers de la liste, vous pouvez utiliser :argaddles :argdeletecommandes ou respectivement.

Une fois que vous êtes satisfait de la liste, vous pouvez maintenant utiliser la puissante :argdocommande de Vim qui exécute une commande pour chaque fichier de la liste d'arguments::argdo %s/search/replace/g

Voici quelques astuces de recherche (basées sur certains commentaires):

  1. Utilisez une limite de mot si vous voulez rechercher "foo" mais pas "foo_bar". Utilisez les constructions \<et \>autour du motif de recherche comme suit::argdo %s/\<search\>/foobar/g
  2. Utilisez un /cindicateur de recherche si vous souhaitez que Vim demande une confirmation avant de remplacer un terme de recherche.
  3. Utilisez un /eindicateur de recherche si vous souhaitez ignorer les erreurs "modèle non trouvé".
  4. Vous pouvez également choisir d'enregistrer le fichier après avoir effectué la recherche: :argdo %s/search/replace/g | update. Ici, :updateest utilisé car il ne sauvegardera le fichier que s’il a changé.

Tampons ouverts

Si vous avez déjà des tampons ouverts sur :bufdolesquels vous souhaitez effectuer la recherche / remplacement, vous pouvez utiliser une commande pour exécuter une commande pour chaque fichier de votre liste de tampons ( :ls).

La commande est très similaire à :argdo: :bufdo %s/search/replace/g

Semblable à :argdoet :bufdo, il existe :windoet :tabdoagit sur les fenêtres et les onglets respectivement. Ils sont moins souvent utilisés mais restent utiles à connaître.

akshay
la source
4
Ce pourrait être une bonne idée d’utiliser le /cdrapeau pour confirmer les substitutions.
Romainl
3
Je recommanderais également l’utilisation de limites de mots \<et \>du searchpour éviter le remplacement partiel des mots.
tommcdo
1
Autre commentaire, le répertoire de travail de vim est par défaut celui où vous avez démarré vim, et non le répertoire du fichier actuel. Vous pouvez définir le répertoire de travail sur le fichier actuel à l'aide de :cd %:p:h. Les autres options du répertoire de travail sont répertoriées dans vim.wikia.com/wiki/Set_working_directory_to_the_current_file .
studgeek
30

Disons que nous avons une structure de projet simple comme celle-ci:

entrez la description de l'image ici

greeting.txt ressemble à

entrez la description de l'image ici

et info / age.txt ressemble à

entrez la description de l'image ici

Disons que nous voulons remplacer toutes les occurrences de Sam par Bob. Voici ce que nous ferions:

  1. Définir le répertoire de travail

    Assurez-vous que le répertoire de travail actuel de Vim est la racine du projet (il ne vous montrera pas comment faire cela ici).

  2. Trouver les fichiers contenant 'Sam'

    Utilisez la commande vimgrep de Vim pour rechercher toutes les occurrences de Sam dans le projet (note: les **/*recherches dans tous les fichiers de manière récursive).

    :vimgrep /Sam/gj **/*
    

    Cela remplira la liste de correctifs avec toutes les instances de Sam. Si vous souhaitez afficher la liste des correctifs rapides, vous pouvez utiliser la commande Vim.:copen entrez la description de l'image ici

  3. Substituer dans tous les fichiers contenant «Sam»

    Maintenant, nous voulons exécuter la commande de substitution de Vim dans chaque fichier de la liste des correctifs. Nous pouvons le faire en utilisant la :cfdo {cmd}commande qui exécute {cmd} dans chaque fichier de la liste des correctifs. Le {cmd} spécifique que nous voulons utiliser est substituteou spour faire court. La ligne complète ressemblerait à ceci:

    :cfdo %s/Sam/Bob/g
    

    Vous pouvez ajouter le drapeau c pour confirmer tous les remplacements si vous le souhaitez:

    :cfdo %s/Sam/Bob/gc
    
  4. Enregistrer tous les fichiers

    :cfdo update
    
Niko Bellic
la source
2
J'aime plus ça. C'est simple et fonctionne avec Ack (ou n'importe quel plugin qui remplit la fenêtre QuickFix).
Zuhaib
1
Ceci est une excellente réponse
Peoplee
2
Obtenait "pas d'écriture depuis le dernier changement", ce cfdo %s/Sam/Bob/g | updatequi
corrige
@ hakunin Je recommanderais de définir l' hiddenoption avec :set hiddensi vous ne l'avez pas déjà fait.
Niko Bellic
3

Bien que ce ne soit pas une solution VIM, si vous utilisez VI / VIM, il peut être plus facile d’utiliser une solution CLI. Pour changer tous les fichiers du répertoire en cours, utilisez-le perlcomme il a été fait pour des situations comme celle-ci:

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

Si vous avez également besoin de le faire dans des sous-répertoires, j’appareille généralement perlavec find:

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

La bonne chose à propos de cela est que vous pouvez facilement affiner la liste en fonction de types de fichiers spécifiques. Par exemple, pour limiter les fichiers python:

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

Pour remplacer une phrase par une autre, vous pouvez utiliser le mode Vim Ex.

Par exemple ( exalias to vim -E):

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

Récursivement dans bash / zsh (avec globstarset, par exemple shopt -s globstar):

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

Récursivement (en utilisant findet ignorer les fichiers cachés tels que les .gitfichiers):

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

Remarque: la :bufdocommande n'est pas POSIX .

Remarque: La syntaxe -not -path '*/\.*'est utilisée pour ignorer les fichiers cachés (tels que .git).

Kenorb
la source
note bufdo n'est pas POSIX pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html
Steven Penny
0

Voici la commande shell utilisant findet exeditor (sans utiliser:bufdo ):

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

Cela éditera tous les *.rbfichiers du dossier actuel (de manière récursive) et les remplacera foopar bar.

Kenorb
la source