web-dev-qa-db-fra.com

Comment remplacer du texte entre deux modèles sur des lignes différentes?

J'ai plusieurs fichiers avec du texte qui doit être remplacé. Le texte commence et se termine avec le même motif à chaque fois, mais le contenu entre les motifs est variable. Les motifs peuvent apparaître au milieu de lignes et le contenu qui les sépare s'étend souvent sur plusieurs lignes.

Il n'y aura qu'une seule occurrence du motif de début et de fin dans chaque fichier.

J'ai besoin d'une méthode de ligne de commande pour remplacer le texte entre les modèles, y compris les modèles eux-mêmes. La sortie dans un nouveau fichier ou la modification sur place convient.

Une commande qui opère sur un seul fichier fonctionnera, car je peux parcourir les fichiers et appliquer la commande moi-même. J'ai essayé une solution sed mais je ne pouvais que remplacer des lignes entières.

Un exemple de texte serait:

Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: Security-Start Bs86gKI-734Lw#32_nP/5589Zfb8Wj-
sW93j9b Security-End, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

Le modèle de départ est Security-Start et le modèle de fin est Security-End. Je souhaite remplacer les modèles et tout le reste par Word REDACTED.

Je voudrais que la sortie soit:

Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

Veuillez noter que le texte entre les deux modèles peut être si long qu'il couvre plusieurs lignes, il est assez aléatoire. Ce n'est pas clair dans l'exemple ci-dessus

Toute langue disponible par défaut sur un système Ubuntu conviendra. Mes premières pensées sont 'sed' ou 'awk', mais tout ce avec quoi vous serez à l'aise ira bien.

5
Arronical

Il devrait fonctionner pour vous:

sed -e '/Security-Start/{ N; s/Security-Start.*Security-End/REDACTED/ }'
  • /Security-Start/ recherche "Security-Start"
  • Si vous l'avez trouvé: "N;" signifie ajouter la ligne suivante.
  • et faites le replacements/Security-Start.*Security-End/REDACTED/ au résultat final.

Pour plus de deux lignes, utilisez celle-ci:

sed -n '1h; 1!H; ${ g; s/Security-Start.*Security-End/REDACTED/p }'

Lire ici

8
Ravexina

Si les fichiers ne sont pas trop volumineux, vous pouvez utiliser Perl en mode Slurp:

$ Perl -0777 -pe 's/Security-Start.*Security-End/REDACTED/s' file 
Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

Le paramètre de ligne de commande -0777 désactive efficacement le séparateur d’enregistrements de sorte que le fichier entier soit insufflé. Le modificateur regex s force Perl à inclure les caractères de nouvelle ligne dans ., ce qui permet à l'expression de correspondre sur toutes les lignes.


Alternativement, avec une boucle sed:

$ sed '/Security-Start/ {:a; $!N; s/Security-Start.*Security-End/REDACTED/; t; ba}' file
Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...

Avec GNU sed, vous pouvez remplacer t; ba (branche en cas de remplacement réussi; (sinon) branchez-le à :a) par Ta (branchez-vous à :a sur n remplacement réussi).

8
steeldriver

Une approche plus manuelle consisterait à remplacer tous les caractères de nouvelle ligne dans le fichier d'entrée par des valeurs NULL. Utilisez une expression rationnelle Perl non-gloutonne pour effectuer le remplacement, puis réinstallez les nouvelles lignes:

$ tr '\n' '\0' < file | 
    Perl -pe 's/Security-Start.*?Security-End/Security: REDACTED/g' |
        tr '\0' '\n'
Cable Type ID:135, Installation ID:62, Alpha Conductor Origin:
Tolerance Report B74 - 3rd June 1996, Beta Conductor Origin: 
Tolerance Report B74 - 3rd June 1996, Phase Conductor Size: 
45mm, Security: Security: REDACTED, Location ID:889, Protective Earth Size:
67mm, Protective Earth Max Current (A): 4, Overload Time...
4
terdon

Voici comment vous pouvez le faire avec awk:

awk -v RS='Security-Start.*Security-End' -v ORS= '1;NR==1{printf "REDACTED"}' file
1
user000001