Je souhaite rechercher et remplacer du texte dans un grand ensemble de fichiers à l'exclusion de certaines instances. Pour chaque ligne, je veux une invite me demandant si je dois remplacer cette ligne ou non. Quelque chose de similaire à vim :%s/from/to/gc
(avec l' c
invite de confirmation), mais sur un ensemble de dossiers. Existe-t-il un bon outil ou script de ligne de commande qui peut être utilisé?
11
s/from/to/g
avec un problème de mise en forme après, plutôts/from/to/gc
qu'avec une emphase sur cellec
que vous avez tenté d'écrire (vous ne pouvez pas le faire avec Markdown, vous pouvez le faire avec<code>
et<strong>
balises HTML).Réponses:
Pourquoi ne pas utiliser vim?
Ouvrez tous les fichiers dans vim
Ou ouvrez uniquement les fichiers pertinents (comme suggéré par Caleb)
Et puis exécutez le remplacement dans tous les tampons
Vous pouvez également le faire avec
sed
, mais mes connaissances en sed sont limitées.la source
grep
au lieu defind
afin que vous n'ouvriez que les fichiers qui ont des correspondances connues.vim $(grep 'from' . -Rl)
Vous pouvez faire quelque chose de grossier avec un petit script Perl qui est chargé d'effectuer des remplacements ligne par ligne (
-l -pe
) en place sur les fichiers passés en arguments (-i
):Les améliorations possibles seraient de colorer certaines parties de l'invite et de prendre en charge des éléments tels que «remplacer toutes les occurrences dans le fichier actuel». Demander séparément chaque occurrence sur une ligne serait plus difficile.
Deuxième partie, correspondance des fichiers. s'il n'y a pas trop de fichiers impliqués et que vous exécutez zsh, vous pouvez faire correspondre récursivement tous les fichiers du répertoire actuel et de ses sous-répertoires:
Si votre shell est bash ≥4, vous pouvez exécuter
perl … **/*
, mais cela produira des messages d'erreur parasites car sed tentera (et échouera) de s'exécuter sur les répertoires. Si vous ne souhaitez effectuer le remplacement que dans un ensemble de fichiers tels que les fichiers C, vous pouvez restreindre les correspondances (cela fonctionne en bash ≥4 ou zsh):Si vous avez besoin d'un contrôle plus fin sur les fichiers que vous remplacez, ou votre shell n'a pas la construction de correspondance de répertoire récursive
**
, ou si vous avez trop de fichiers et obtenez une erreur «ligne de commande trop longue», utilisezfind
. Par exemple, pour effectuer un remplacement dans tous les fichiers nommés*.h
ou*.c
dans le répertoire en cours et ses sous-répertoires (sur les anciens systèmes, vous devrez peut-être utiliser\;
plutôt+
qu'à la fin de la ligne (le+
formulaire est plus rapide mais n'est pas disponible partout)).Cela étant dit, je m'en tiendrai à un éditeur interactif si vous avez besoin d'interaction. Gert a montré un moyen d'y parvenir dans Vim , bien qu'il nécessite d'ouvrir tous les fichiers que vous souhaitez rechercher, ce qui peut être un problème s'il y en a beaucoup.
Dans Emacs, voici comment procéder:
M-x find-name-dired
(spécifiez un répertoire de niveau supérieur) ouM-x find-dired
(spécifiez unefind
ligne de commande arbitraire ).t
pour marquer tous les fichiers, puis surQ
(dired-do-query-replace-regexp
) pour effectuer un remplacement avec invite sur les fichiers marqués.la source
sdiff
(voir http://www.gnu.org/software/diffutils/manual/diffutils.html#Invoking-sdiff ) pourrait être utile ici. Avec lui, vous pouvez faire des correctifs interactifs. Donc, le faire avec un fichier temporaire que vous avez créé en effectuant des opérations de remplacement à l'aide desed
peut être une solution possible:(Boucle de fichier utilisant une substitution de processus non-POSIX et prise
read -d
en charge par exemple parbash
.)la source