sed remplace plusieurs motifs avec certains cordes

1

J'ai été chargé de remplacer un grand nombre d'identifiants codés en dur dans certains codes (par exemple: private static String MERCHANT_ID = "1234"; ) avec des références à un fichier de configuration quelque part (la version remplacée pour cet exemple doit donc être private static String MERCHANT_ID = ConstantMerchants.MERCHANT_A; ).

La fonction de recherche et de remplacement par défaut dans Eclipse aurait ça ira si je ne remplaçais que quelques pièces d'identité, mais je ne le suis pas. J'ai vingt projets, tous contiennent des centaines de fichiers avec plusieurs notations différentes de l'ancienne chaîne.

J'ai déjà compilé une liste de motifs de regex qui correspondent à toutes les notations possibles.

Est-il possible d'utiliser sed pour remplacer toutes les anciennes chaînes par les nouvelles versions en disposant un fichier de configuration quelque part contenant l'ancien modèle, et par quoi il devrait être remplacé?

Je cherche quelque chose qui me permette de définir des motifs avec une nouvelle valeur, pensez à quelque chose de similaire à ceci:

# old | new
/merchantId:\s*("|')1234("|'),/|merchantId: ConstantMerchants.MERCHANT_A
/private static String MERCHANT_ID\s*=\s*("|')1234("|');/|private static String MERCHANT_ID = ConstantMerchants.MERCHANT_A

Si je devais utiliser un autre outil qui pourrait m'aider à mieux résoudre ce problème, j'aimerais en entendre parler. J'aimerais beaucoup utiliser la nouvelle fonctionnalité Bash sur Windows, mais c'est uniquement parce qu'elle a l'air cool :)

cascer1
la source
Je ne sais pas quel est votre problème: ne pouvez-vous pas faire travailler vos RE? sed syntaxe, ou ne pouvez-vous pas obtenir sed travailler sur plusieurs fichiers, ou quoi?
AFH
Je ne trouve pas comment écrire un seul sed commande qui effectue tous les remplacements, en utilisant plusieurs fichiers regex et
cascer1
Dans sed vous pouvez utiliser le -e possibilité de faire autant de substitutions à autant de fichiers que nécessaire en une seule fois, par exemple sed -i -e 's/old1/new1/' -e 's/old2/new2' ... file1 file2 .... Si les fichiers ne se trouvent pas tous dans un seul répertoire ou au même niveau dans une arborescence de sous-répertoires, vous permettant de les sélectionner avec une correspondance de caractère générique, vous pouvez utiliser find et xargs pour construire la chaîne d'exécution.
AFH
Si vous ne connaissez pas trop sed, ce est une bonne référence.
AFH

Réponses:

2

Si je comprends bien, le problème est que vous avez un ensemble de modèles de syntaxe à faire correspondre, et indépendamment, un grand nombre de nombres possibles devant être traduits, et vous devez les "multiplier" ensemble. Ce qui suit pourrait être un bon sed mécanisme, en supposant une simplification: dans votre sed Commencez par utiliser les modèles pour faire correspondre les lignes, puis utilisez la conversion de nombre sur ces lignes. Par exemple créer un fichier sedscript en portant

/merchantId:\s*("|')[0-9]+("|')/b change
/private static String MERCHANT_ID\s*=\s*("|')[0-9]+("|')/b change
b
:change
s/["']1234["']/ConstantMerchants.MERCHANT_A/
s/["']1235["']/ConstantMerchants.MERCHANT_B/

Cela commence par chacun de vos patterns suivi de la commande b change ce qui signifie branche à l'étiquette change quand le motif est trouvé. La liste des modèles se termine par la commande b ce qui signifie aller à la fin, c’est-à-dire passer à la prochaine ligne d’entrée du fichier.

le :change signifie que c'est l'étiquette change où nous branchons à. Suit ensuite chacun de vos numéros possibles pour nommer les traductions. La simplification consiste à supposer qu’un seul nombre entre guillemets apparaîtra sur la ligne afin que nous puissions ignorer quel modèle correspond. S'il y a des exceptions à cela, il peut être intéressant de les gérer à la main.

Sur un système Unix (je ne connais pas Windows), vous pouvez utiliser ce script pour éditer les fichiers:

find dir -type f |
xargs sed -i -r -f sedscript

le -i éditera les fichiers sur place, donc commencez toujours par copier les fichiers vers un nouveau répertoire dir, puis exécutez cette commande sur la copie et utilisez diff -ru entre les deux répertoires pour vérifier qu’il fait ce que vous voulez. le -r est nécessaire (sous Unix) pour que GNU sed accepte (a|b) au lieu de l'habituel \(a\|b\) modèle.

meuh
la source
Merci, c'est une solution beaucoup plus propre que les horreurs que j'ai inventées jusqu'à présent. Je n'ai en effet qu'un seul identifiant par ligne à tout moment. Votre solution avec le change label permet également de réduire le nombre de commandes à ajouter.
cascer1
1

En regardant le HOMME Page vous verrez que sed soutient un -f paramètre pour fournir un fichier de script. Ce fichier doit contenir tous les éléments de remplacement à exécuter comme vous le fournissez. sed directement. Donc, par exemple vous auriez:

  • s/old/new/
  • s/new/old/

Sur des lignes séparées du fichier, les deux commandes seront appliquées à tout ce que vous fournissez en stdout. Par exemple: echo "old" | sed -f script.file avec le contenu ci-dessus conduirait à la sortie ancienne.

Pour appliquer ces règles à plusieurs fichiers, une option serait d’utiliser une boucle dans laquelle vous exécutez sed avec le script pour chaque fichier et enregistrez les modifications apportées au fichier lui-même. Une autre serait d'utiliser l'option -i et fournit "tous" les fichiers comme arguments de ligne de commande. En fonction du nombre, vous pouvez rencontrer des problèmes avec la longueur totale de la commande.

Seth
la source
Merci. Je suppose qu’il est possible d’exécuter d’abord grep pour rechercher tous les fichiers contenant une correspondance, puis diriger la sortie vers sed pour les modifier?
cascer1
Certainement. Vous aurez juste à trouver un script pour le faire. Une possibilité serait d’exécuter le grep pour obtenir le nom et le compiler dans une variable qui est transmise comme paramètre de fichier pour sed. Je suis sûr qu'il est possible de faire quelque chose comme ça, mais pas comment.
Seth