Utiliser Emacs pour rechercher et remplacer de façon récursive dans les fichiers texte qui ne sont pas déjà ouverts

comme suite à cette question , c'est essayer de savoir comment faire quelque chose comme ça qui devrait être facile, qui m'empêche surtout de m'habituer à utiliser Emacs et à la place de démarrer L'éditeur que je connais déjà. J'utilise cet exemple assez souvent pour éditer plusieurs fichiers.

dans Ultraedit je ferais Alt+S puis p pour afficher une boîte de dialogue avec les options: Find (inclut l'utilisation d'expressions régulières à travers plusieurs lines), remplacer par, dans les fichiers / Types, répertoire, case de correspondance, Match mot entier seulement, Liste des fichiers modifiés et sous-répertoires de recherche. Habituellement, je vais d'abord utiliser la souris pour cliquer-glisser sélectionnez le texte que je veux remplacer.

utilisant seulement Emacs lui-même (sur Windows XP), sans appeler aucun utilitaire externe, comment remplacer tous foonbar avec barnbaz dans *.c et *.h fichiers dans un dossier et tous les dossiers sous elle. Peut-être Emacs n'est pas le meilleur outil pour ce faire avec, mais comment peut-il être fait facilement avec un minimum de commande?

191
demandé sur Community 2008-11-07 04:02:58

13 réponses

  1. M-x find-name-dired : vous serez invité pour un répertoire racine et un motif de nom de fichier.
  2. Appuyez sur t pour "changer de marque" pour tous les fichiers trouvés.
  3. Appuyez sur Q pour "Query-replace dans les Fichiers...": vous serez invité pour requête / regexps de substitution.
  4. procéder comme avec query-replace-regexp : SPACE pour remplacer et passer au match suivant, n pour sauter un match, etc.
  5. appuyez sur C-x s pour sauvegarder les tampons. (Vous pouvez ensuite appuyer sur y , n ou ! pour tout sauvegarder en une seule fois)
336
répondu Chris Conway 2017-09-12 12:42:28
  • M-x find-name-dired RET
    • il se peut qu'il faille un certain temps pour que tous les fichiers apparaissent dans la liste, faites défiler vers le bas ( M-> ) jusqu'à ce que " find finished "apparaisse pour s'assurer qu'ils ont tous chargé
  • Appuyez sur t à "basculer" tous les fichiers
  • Appuyez sur Q pour "Query-replace dans les Fichiers...": vous serez invité pour requête / regexps de substitution.
  • procéder comme avec query-replace-regexp: SPACE ou y pour remplacer et passer à la correspondance suivante, n pour sauter une correspondance, etc.
    • Type ! pour remplacer tous les événements dans le fichier courant sans demander, N pour sauter tous les remplacements possibles pour le reste du fichier courant. ( N est emacs 23+ uniquement)
    • pour effectuer le remplacement sur tous les fichiers sans autre demande, tapez Y .
  • appeler "ibuffer" ( C-x C-b si lié à ibuffer, ou M-x ibuffer RET ) pour lister tous les fichiers ouverts.
  • Type * u pour marquer tous les fichiers non enregistrés, de type S pour enregistrer tous les fichiers marqués
  • * * RET pour marquer toutes les marques, ou tapez D pour fermer tous les fichiers marqués

cette réponse est combinée de cette réponse , de ce site , et de mes propres notes. En Utilisant Emacs 23+.

34
répondu Frank Henard 2017-05-23 12:10:33

j'utilise généralement d'autres outils pour effectuer cette tâche, et il semble que beaucoup des approches mentionnées à Emacswiki trouver et remplacer à travers l'entrée de fichiers shell out, mais le paquet Findr semble très prometteur.

Voler une partie de la source du fichier :

(defun findr-query-replace (from to name dir)
  "Do `query-replace-regexp' of FROM with TO, on each file found by findr.
12
répondu Blair Conrad 2008-11-07 01:52:04

Les réponses fournies sont grands, mais je pensais que je voudrais ajouter une approche légèrement différente.

c'est une méthode plus interactive, et nécessite wgrep , rgrep et iedit . Les deux iedit et wgrep doivent être installés par MELPA ou marmelade (en utilisant M-x package-list-packages )

Première M-x rgrep pour rechercher la chaîne que vous recherchez.

vous serez en mesure de spécifier les types de fichiers/pattern et le dossier de manière récursive.

ensuite, vous devrez exécuter wgrep démarrer avec C-s C-p .

Wgrep vous permettra d'éditer les résultats rgrep , donc définissez une région sur la chaîne de caractères pour faire correspondre et démarrer iedit-mode avec C-; (selon votre terminal, vous pourriez avoir besoin de re-lier cela)

tous les événements seront modifiables en une seule fois. "1519120920 de" commettre wgrep . Puis C-x s ! pour sauver le modifié fichier.

Le principal avantage de cette méthode est que vous pouvez utiliser iedit-mode pour désactiver certains matchs M-; . Vous pouvez également utiliser les résultats dans rgrep pour sauter dans les fichiers, par exemple si vous avez un imprévu match.

je le trouve très utile pour faire des modifications de source et renommer des symboles (variables, noms de fonction, etc.) sur l'ensemble du projet.

si vous ne savez pas déjà / utilisez le mode iedit c'est très pratique outil, je vous recommande fortement de donner un coup d'oeil.

10
répondu ocodo 2013-12-17 01:34:43

L'utilisation de dired pour revenir en bas d'un arbre de répertoire profond va être un peu lent pour cette tâche. Vous pourriez envisager d'utiliser tags-query-remplacer . Cela signifie qu'il faut s'élancer pour créer une table tags, mais c'est souvent utile de toute façon, et c'est rapide.

5
répondu Alex Coventry 2008-11-07 12:56:02

Projectile est vraiment agréable: C-c P R exécute le projectile de commande-Remplacer

5
répondu eflanigan00 2016-12-02 19:00:30

Source d'information: 1

pour les utilisateurs d'emacs pro:

  1. appel dirigé pour lister les fichiers dans dir, ou appel find-dired si vous avez besoin de tous les sous-répertoires.
  2. marquez les fichiers que vous voulez. Vous pouvez marquer par regex en tapant pax.
  3. Tapez Q pour appeler dired-do-query-replace-regexp.
  4. Tapez votre find regex et remplacez string. 〔☛ common elisp regex pattern"
  5. pour chaque événement, type y à remplacer, n À Sauter. Type de contrat Ctrl+G can avorter l'ensemble de l'opération.
  6. Type
  7. ! pour remplacer tous les événements dans le fichier courant sans demander, N de sauter tous les remplacements possibles pour le reste du fichier courant. (N est emacs 23 uniquement)
  8. pour effectuer le remplacement sur tous les fichiers sans autre demande, tapez Y. (Emacs 23 seulement)
  9. appeler ibuffer pour tout ouvrir fichier. Type 【* u】 pour marquer tous les fichiers non enregistrés, type S pour enregistrer tous les fichiers marqués, type de D pour les fermer toutes.

guide étape par étape pour les débutants Emacs

Sélectionner Les Fichiers Cibles

Démarrer emacs en tapant "emacs" dans l'interface de ligne de commande d'invite. (Ou, double-cliquez L'icône Emacs si vous êtes dans un environnement D'Interface utilisateur graphique)

sélectionner des fichiers dans un répertoire

vous devez d'abord sélectionner les fichiers que vous voulez remplacer. Utilisez le menu graphique po ur ouvrir le répertoire. Emacs vous demandera un chemin de répertoire. Tapez le chemin du répertoire, puis appuyez sur Entrée.

Maintenant, vous allez voir la liste des fichiers, et maintenant vous devez marquer les fichiers sur lesquels vous voulez que le regex find/replace fonctionne. Vous marquez un fichier en déplaçant le curseur sur le fichier que vous voulez, puis appuyez sur M. Détachez - le en appuyant sur U. (To list subdirectories, move votre curseur sur le répertoire et appuyez sur I. Le contenu du sous-répertoire sera listé en bas.) Pour marquer tous les fichiers par un regex, tapez "p", puis tapez votre motif regex. Par exemple, si vous voulez marquer tous les fichiers HTML, tapez alors "pip".HTML.$ (Vous pouvez trouver une liste des commandes mark dans le menu graphique "Mark" (Ce menu apparaît lorsque vous êtes en mode dirigé).)

sélection de fichiers dans un répertoire et tous ses sous-répertoires

si vous vous voulez faire trouver / remplacer sur des fichiers à l'intérieur d'un répertoire, y compris des centaines de sous-répertoires, voici une méthode pour sélectionner tous ces fichiers.

appelez find-dired. (vous appelez une commande en appuyant sur Option Alt+X Monet) alors, tapez un nom de répertoire, փ / Users / mary /myfiles

Note: Si vous utilisez emacs sur un terminal de texte non graphique unix, et si la Option Alt+X փ ne fonctionne pas, la touche clé équivalente est l'option ESC x փ.

Emacs vous demandera avec le prompt "Exécuter en trouver (avec des arguments): ". Si vous avez besoin de faire le remplacement sur tous les fichiers HTML, alors tapez-nom "*html". Si vous ne vous souciez pas de quel type de fichier mais simplement de tous les fichiers sous ce dir, alors donnez "-type f".

Maintenant, marquez les fichiers comme décrit ci-dessus.

"151900920 Interactif" Rechercher/Remplacer

maintenant, vous êtes prêt à faire le remplacement de find interactif. Pour simplifier, disons que vous voulez juste de remplacer le mot "rapide" par "super". Maintenant, appelez - dired-do-query-replace-regexp. Il vous demandera la chaîne regex et la chaîne de remplacement. Tapez "rapide", Entrez, puis "super".

maintenant, emacs va utiliser votre motif et vérifier les fichiers, et s'arrêter et vous montrer chaque fois qu'une correspondance s'est produite. Lorsque cela se produit, emacs vous demande, et vous avez le choix de faire le changement ou d'ignorer le changement. Pour faire le changement, tapez Y. Pour sauter, tapez N. Si vous voulez simplement qu'emacs fasse toutes ces modifications dans le fichier courant, type de !.

si vous voulez annuler l'ensemble de l'opération sans enregistrer les changements que vous avez faits, tapez փ Ctrl+G փ փ փ, puis quittez emacs en utilisant le menu փ file փ փ փ Exit Emacs փ.

enregistrer les fichiers modifiés

maintenant, après que vous avez traversé l'épreuve ci-dessus, il y a une étape de plus que vous devez faire, et qui est de sauvegarder les fichiers modifiés.

si vous utilisez la version 22 ou une version ultérieure d'emacs, appelez ibuffer pour entrer dans un buffer liste mode, puis tapez 【* u】 pour marquer tous les fichiers non enregistrés, puis tapez S pour les sauver tous. (maj-s)

si vous utilisez une version 21 d'emacs, alors vous pouvez faire ceci: appeler des tampons de liste, puis déplacer le curseur vers le fichier que vous voulez enregistrer et taper. Il marquera le fichier pour enregistrer plus tard l'action. Tapez u à unmark. Une fois que vous avez terminé, tapez x pour exécuter la sauvegarde de tous les fichiers marqués pour la sauvegarde. (dans emacs, le fichier ouvert est appelé "buffer". Ignorer les autres choses.)

Alternative aux options ci-dessus, vous pouvez également appeler save-some-buffers փ Ctrl+x s փ. Ensuite, emacs affichera chaque fichier non sauvegardé et vous demandera si vous voulez qu'il soit sauvegardé.

Note: le regex d'emacs n'est pas le même que Perl ou Python, mais similaire. Pour un résumé et des modèles communs, voir: Emacs Regex.

4
répondu scrapcodes 2013-12-24 06:45:01

M-X Dired , et t pour sélectionner tous les fichiers, et Q à une requête de remplacement de texte dans chacun d'eux. Vous pouvez étendre un sous-répertoire en utilisant la commande i avant la requête-replace. Si vous donnez un préfixe (control-u) à la commande i, il vous demandera pour arg, et-R argument sera d'étendre de façon récursive tous subdirs dans le tampon dired . Donc maintenant vous pouvez interroger-rechercher chaque dossier dans un répertoire entier.

3
répondu Zack Murray 2013-10-22 20:59:55

pour les tampons ouverts, c'est ce que je fais:

(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)))))
2
répondu yPhil 2012-07-27 15:36:38

une autre option est d'utiliser Icicles search . Il s'agit d'un autre type de recherche incrémentale qui utilise l'achèvement de votre entrée minibuffer contre des résultats de recherche. Au fur et à mesure que vous modifiez vos entrées actuelles, l'ensemble des hits correspondants est mis à jour dans la mémoire tampon *Completions* .

vous pouvez rechercher n'importe quel nombre de dossiers, tampons, ou emplacements de marque-page, que vous pouvez choisir en utilisant le motif de minibuffer (par exemple regexp) correspondant.

quand vous vous pouvez remplacer sur demande soit le hit entier ou juste la partie de celui-ci qui correspond à votre entrée minibuffer actuelle. Le remplacement à la demande signifie que vous n'êtes pas interrogé au sujet de chaque résultat de recherche à tour de rôle; vous accédez aux résultats que vous voulez directement, dans n'importe quel ordre. Cette approche peut être plus efficace que query-replace si vous avez un nombre limité de remplacements à faire: vous sautez l'interrogation exhaustive y/n .

la recherche est terminée rechercher contextes que vous définissez -- vous n'êtes pas limité à rechercher tout le texte dans les fichiers cibles (par exemple, vous pouvez sauter des commentaires ou des types particuliers de sections de programme). Un exemple simple de contexte de recherche est une ligne, comme dans grep , mais un contexte peut être n'importe quel bloc de texte que vous aimez. Typiquement, vous définissez les contextes de recherche en utilisant un regexp, mais vous pouvez à la place utiliser une fonction. En plus de définir votre propre, Il ya des Icicles prédéfinis commandes de recherche pour différents types de contextes: blocs de propriétés de texte ou propriétés de superposition, choses-à-point, etc.

vous pouvez aussi trier la recherche frappe dans divers ordres de tri pour faciliter l'accès/la navigation.

1
répondu Drew 2013-08-24 16:55:32

find-name-dired est OK, mais:

  • tous les fichiers que vous obtenez correspondent au même, un seul regexp.
  • find-dired est plus souple à cet égard, mais il est également conçu pour utiliser des règles générales (même si elles peuvent être arbitrairement complexes). Et bien sûr find a son propre langage complexe.
  • si vous voulez alors agir sur seulement quelques-uns des fichiers dont les noms ont été recueillis dans le tampon find(-name)-dired , vous besoin de les marquer ou supprimer / omettre les lignes de ceux que vous ne voulez pas agir.

une alternative est d'utiliser Dired+ les commandes qui agissent sur (a) les fichiers marqués et (b) tous les fichiers marqués (ou tous les fichiers, si aucun n'est marqué) dans les sous-répertoires marqués ... trouvé récursivement . Cela vous donne à la fois généralité et facile contrôle sur le choix du fichier. Ces commandes " here-and-below "sont toutes sur la touche de préfixe M-+ en mode dirigé.

par exemple, M-+ Q est le même que Q - - - query-replace, mais les fichiers cibles sont tous ceux marqués dans le dir actuel et dans tous les sous-dirs marqués, vers le bas, vers le bas...

Oui, une alternative à l'utilisation de tel ici et ci-dessous commandes insérer tous les sous-répertoires et leurs sous-répertoires, de façon récursive, puis utilisez une commande de haut niveau comme Q . Mais il peut souvent être pratique de ne pas s'embêter avec des sous-répertoires insérés.

et pour ce faire, vous avez de toute façon besoin d'un moyen rapide à insérer tous ces sous-répertoires récursivement . Ici aussi, Dired+ peut aider. M-+ M-i insère tous les sous-répertoires marqués et leurs propres sous-répertoires Marqués, de façon récursive. Que is, il est comme M-i (qui insère les sousdirs marqués dans Dired+ ), mais il agit récursivement sur les sousdirs.

(toutes les commandes" ici-et-dessous " dirigées+ sont sur le menu Multiple > marquées ici et en dessous .)

vous pouvez également effectuer des opérations dirigées sur un Emacs fileset , qui est un ensemble enregistré de noms de fichiers situé n'importe où. Et si vous utilisez Glaçons , alors vous pouvez ouvrir un Dired tampon pour seulement les fichiers dans un fileset ou d'autres types de fichier enregistré listes.

vous pouvez aussi bookmark n'importe quel tampon, y compris celui que vous créez en utilisant find(-name)-dired . Cela vous donne un moyen rapide de revenir à un tel ensemble (par exemple un ensemble de projet) plus tard. Et si vous utilisez marque-page+ puis le bookmarking d'un tampon dirigé enregistre (a) ses commutateurs ls , (b) quels fichiers sont marqués, (c) quels sous-répertoires sont insérés, et (d)quels (sous) répertoires sont cachés. Tout cela est restauré lorsque vous "sauter" vers le signet. marque-page+ vous permet également de marquer un arbre entier de tampons dirigés - - saut à la marque - page rétablit tous les tampons dans l'arbre.

1
répondu Drew 2014-01-26 20:52:34

je voudrais suggérer un autre grand outil qui n'a pas encore été mentionné, à savoir Helm .

c'est un excellent remplacement pour de nombreuses opérations standard D'Emacs impliquant l'achèvement, la recherche, etc. En particulier, helm-find-files permet d'effectuer le remplacement de requête (y compris regexp) dans plusieurs fichiers sélectionnés.

Just open helm-find-files , marquer les fichiers pertinents avec M-SPC puis utilisez F6 ou F7 pour lancer la requête remplacer ou la requête remplacer regexp dans les fichiers sélectionnés.

1
répondu Andrzej Pronobis 2015-05-25 03:35:09

ce n'est pas Emacs, mais xxdiff est livré avec un outil appelé xx-rename qui le fera pour plusieurs chaînes à la fois (par exemple de à de à de à), avec des invites interactives, sauvegarde des sauvegardes de tous les fichiers modifiés, et produit un petit journal des modifications faites avec le contexte. C'est ce que j'ai tendance à utiliser quand je fais de grands/global renamings.

-2
répondu blais 2012-08-15 16:12:54