134 votes

Recherche et remplacement dans Vim dans tous les fichiers du projet

Je cherche le meilleur moyen de faire des recherches et des remplacements (avec confirmation) dans tous les fichiers du projet dans Vim. Par "fichiers de projet", j'entends les fichiers du répertoire courant, dont certains ne doivent pas nécessairement être ouverts.

Une façon de procéder pourrait être d'ouvrir simplement tous les fichiers du répertoire courant :

:args ./**

et ensuite faire la recherche et le remplacement sur tous les fichiers ouverts :

:argdo %s/Search/Replace/gce

Cependant, lorsque je fais cela, l'utilisation de la mémoire de Vim passe de quelques dizaines de Mo à plus de 2 Go, ce qui ne me convient pas.

J'ai aussi le EasyGrep installé, mais il ne fonctionne presque jamais - soit il ne trouve pas toutes les occurrences, soit il se bloque jusqu'à ce que j'appuie sur la touche CtrlC . Jusqu'à présent, ma méthode préférée pour accomplir cette tâche consiste à ack-grep pour le terme recherché, en utilisant sa fenêtre de correction rapide, ouvrir tout fichier qui contient le terme et qui n'a pas été ouvert auparavant, et enfin :bufdo %s/Search/Replace/gce .

Je suis à la recherche d'un bon plugin qui pourrait être utilisé pour cela, ou bien d'une commande ou d'une séquence de commandes qui serait plus simple que celle que j'utilise actuellement.

1 votes

@Cascabel Depuis que vous avez écrit ce commentaire, il existe un site vi.stackexchange.com.

115voto

Jefromi Points 127932

L'autre grande option ici est tout simplement de ne pas utiliser vim :

sed -i 's/pattern/replacement/' <files>

ou si vous avez un moyen de générer une liste de fichiers, peut-être quelque chose comme ceci :

find . -name *.cpp | xargs sed -i 's/pattern/replacement/'
grep -rl 'pattern1' | xargs sed -i 's/pattern2/replacement/'

et ainsi de suite !

0 votes

Merci. J'ai vraiment besoin d'apprendre ces trucs de ligne de commande de la vieille école. Je pense que c'est la meilleure réponse. Ces regex sont-ils des regex perl ou des regex vim ou un autre type de regex ?

2 votes

@EricJohnson : Ils sont... sed qui sont essentiellement des expressions régulières de base POSIX.2, mais pas exactement (ceci est dans la page de manuel) - elles permettent à \n correspond aux nouvelles lignes, et d'autres choses similaires. Ils sont donc à peu près les mêmes que grep les expressions régulières.

0 votes

Y a-t-il une raison pour laquelle vous avez -i dans la commande sed ? La page de manuel dit que c'est pour spécifier une extension, mais vous ne semblez pas en spécifier une.

35voto

Eric Johnson Points 5217

J'ai décidé d'utiliser ack et Perl pour résoudre ce problème afin de profiter des expressions régulières plus puissantes de Perl plutôt que du sous-ensemble GNU.

ack -l 'pattern' | xargs perl -pi -E 's/pattern/replacement/g'

Explication

ack

ack est un outil de ligne de commande génial qui est un mélange de grep , find et les expressions régulières Perl complètes (pas seulement le sous-ensemble GNU). Il est écrit en Perl pur, il est rapide, il a une coloration syntaxique, il fonctionne sous Windows et il est plus convivial pour les programmeurs que les outils de ligne de commande traditionnels. Installez-le sur Ubuntu avec sudo apt-get install ack-grep .

xargs

Xargs est un ancien outil de ligne de commande Unix. Il lit les éléments de l'entrée standard et exécute la commande spécifiée suivie des éléments lus pour l'entrée standard. Ainsi, la liste des fichiers générés par ack est ajoutée à la fin de la commande perl -pi -E 's/pattern/replacemnt/g' commandement.

perl -pi

Perl est un langage de programmation. L'option -p permet à Perl de créer une boucle autour de votre programme qui itère sur les arguments du nom de fichier. L'option -i permet à Perl d'éditer le fichier en place. Vous pouvez modifier cette option pour créer des sauvegardes. L'option -E permet à Perl d'exécuter la ligne de code spécifiée comme étant le programme. Dans notre cas, le programme est juste une substitution de regex en Perl. Pour plus d'informations sur les options de ligne de commande Perl perldoc perlrun . Pour plus d'informations sur Perl, voir http://www.perl.org/ .

0 votes

J'aime cette réponse car elle fonctionne même avec les terminaisons de ligne de Cygwin. Notez qu'elle ajoute un \r à la fin des lignes modifiées, mais en utilisant sed, il remplacera chaque newline, rendant vos diffs inutilisables. Perl est un peu plus sain d'esprit, et c'est un excellent outil de recherche et de remplacement. Merci !

0 votes

@andrew, je ne sais pas exactement ce qui ne va pas dans votre cas. Cela vous aiderait-il d'utiliser \R au lieu de \n dans vos regexps ? Voir \R section dans perldoc.perl.org/perlrebackslash.html#Divers . Essayez aussi perldoc.perl.org/perlre.html#Regular-Expressions . Perl est extrêmement multiplateforme et je suis sûr qu'il existe un moyen pour vous de ne pas vous retrouver avec des fins de lignes tronquées.

0 votes

Ma regex n'a pas de nouvelles lignes, les versions cygwin de ces programmes ajoutent automatiquement \r à la fin de chaque ligne modifiée. J'ai particulièrement aimé la version perl parce qu'elle ne modifie que les lignes qu'elle correspond, alors que sed modifiera tous même si elles ne correspondent pas à l'expression rationnelle.

27voto

tuxcanfly Points 1156

Greplace fonctionne bien pour moi.

Il y a aussi un version prête pour le pathogène sur github.

8 votes

Je l'ai installé, je vois les autres commandes comme :Gsearch et :Gbuffersearch existent, mais quand je tape :Greplace Je reçois Not an editor command: Greplace .

0 votes

Selon la docs, la syntaxe est : :Gsearch [<grep-option(s)>] [[<pattern>] [<filename(s)>]] donc vous pourriez faire une recherche récursive en utilisant, par exemple : :Gsearch -r pattern dir/

0 votes

Ce que je déteste dans Greplace, c'est que si le motif se trouve dans le nom du fichier, Greplace échoue, car vous finissez par le remplacer dans le nom du fichier également.

24voto

Benoit Points 35553

Peut-être faire ça :

:noautocmd vim /Search/ **/*
:set hidden
:cfirst
qa
:%s//Replace/gce
:cnf
q
1000@a
:wa

Explication :

  • :noautocmd vim /Search/ **/* ⇒ recherche ( vim est l'abréviation de vimgrep ) dans tous les fichiers de tous les sous-répertoires du cwd sans déclencher les autocmds ( :noautocmd ), pour des raisons de rapidité.
  • :set hidden ⇒ permettre d'avoir des tampons modifiés non affichés dans une fenêtre (pourrait être dans votre vimrc).
  • :cfirst ⇒ passer au premier résultat de la recherche
  • qa ⇒ début de l'enregistrement d'une macro dans le registre. a
  • :%s//Replace/gce ⇒ remplacer toutes les occurrences du dernier motif de recherche (toujours /Search/ à ce moment-là) avec Replace :
    • plusieurs fois sur une même ligne ( g drapeau)
    • avec confirmation de l'utilisateur ( c drapeau)
    • sans erreur si aucun motif n'est trouvé ( e drapeau)
  • :cnf ⇒ passer au fichier suivant dans la liste créée par la fonction vim commande
  • q ⇒ arrêter la macro d'enregistrement
  • 1000@a ⇒ jouer la macro stockée dans le registre un millier de fois
  • :wa ⇒ sauvegarder tous les tampons modifiés

* EDIT * Vim 8 way :

À partir de Vim 8, il existe une meilleure façon de procéder, comme suit :cfdo itère sur tous les fichiers de la liste des corrections rapides :

:noautocmd vim /Search/ **/*
:set hidden
:cfdo %s//Replace/gce
:wa

0 votes

Vous pourriez expliquer cela un peu plus en détail pour nous, petits mortels. Je ne vois pas bien si vous devez faire cette "séquence" à chaque fois. Je suis plus rapide à le faire en utilisant mon vieux Delphi 5 rouillé, donc je dois sûrement manquer quelque chose.

1 votes

@Lieven : Vous avez raison, c'est un peu obscur sans commentaires. Je vais développer une explication.

0 votes

+1 mais bien que vim m'a conquis pour beaucoup de choses, je pense que je vais m'en tenir à PowerGrep pour cette fois.

23voto

exbinary Points 571

Remplir :args à partir d'une commande shell

Il est possible (sur certains systèmes d'exploitation 1 )) pour fournir les fichiers pour :args via une commande shell.

Par exemple, si vous avez ack 2 installé,

:args `ack -l pattern`

demandera à ack de retourner une liste de fichiers contenant 'pattern' et les mettra dans la liste des arguments.

Ou avec le bon vieux grep, je suppose :

:args `grep -lr pattern .`  

Vous pouvez alors simplement utiliser :argdo comme décrit par le PO :

:argdo %s/pattern/replacement/gce

Remplir :args de la liste des solutions rapides

Consultez également réponse de nelstrom à une question connexe décrivant une commande simple définie par l'utilisateur qui remplit l'arglist à partir de la liste actuelle des corrections rapides. Cela fonctionne très bien avec de nombreuses commandes et plugins dont la sortie se retrouve dans la liste des corrections rapides ( :vimgrep , :Ack 3 , :Ggrep 4 ).

La séquence permettant d'effectuer une recherche à l'échelle du projet pourrait alors être réalisée :

:vimgrep /pattern/ **/*
:Qargs 
:argdo %s/findme/replacement/gc

:Qargs est l'appel à la commande définie par l'utilisateur qui remplit l'arglist à partir de la liste des corrections rapides.

Vous trouverez également des liens dans la section discussion suivante à des plugins simples qui ramènent ce flux de travail à 2 ou 3 commandes.

Liens

  1. :h {arglist} - vimdoc.sourceforge.net/htmldoc/editing.html#{arglist}
  2. ack - betterthangrep.com/
  3. ack.vim - github.com/mileszs/ack.vim
  4. fugitif - github.com/tpope/vim-fugitive

1 votes

Argdo s'arrête après le premier fichier avec un problème d'écriture

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X