2 votes

utiliser sed pour remplacer deux motifs dans un motif plus grand

En utilisant sed, comment pourrais-je remplacer deux motifs dans un motif plus grand sur une seule ligne ?

À partir d'une seule ligne de texte, je veux trouver un motif (appelons-le motif extérieur), puis remplacer deux motifs intérieurs par ce motif extérieur.

Voici un exemple d'une ligne de texte d'entrée :

Z:\source\private\main\developer\foo\setenv.sh(25):     export 'FONTCONFIG_PATH'="$WINE_SHARED_SUPPORT/X11/etc/fonts"

Dans l'exemple ci-dessus, le motif extérieur est /^.*\([[:digit:]]+\):/ qui devrait être égal à Z:\source\private\main\developer\foo\setenv.sh(25): Les deux modèles intérieurs sont /^[A-Za-z]:/ y /\\/ .

Une autre façon de formuler ma question est :

En utilisant sed Je sais comment effectuer des remplacements d'un motif en utilisant la fonction s mais comment limiter la portée de la commande s de sorte qu'elle ne fonctionne que sur la partie de la chaîne d'entrée jusqu'à l'élément (25): ?

Le résultat final que j'essaie d'obtenir est que la ligne de texte est transformée en ceci :

/enlistments/source/private/main/developer/foo/setenv.sh(25):     export 'FONTCONFIG_PATH'="$WINE_SHARED_SUPPORT/X11/etc/fonts"

1voto

Damian Powell Points 315

Cette commande convertit votre exemple d'entrée en votre exemple de sortie :

sed 's|\\|/|g;s|^[^/]*|/enlistments|'

Si certaines de vos entrées contiennent des barres obliques inverses dans la partie qui suit l'élément /^.*([[:digit:]]+):/ vous devrez alors diviser et conquérir pour éviter que ces derniers antislashs soient remplacés.

sed 'h;s/^.*([[:digit:]]\+)://;x;s/^\(.*([[:digit:]]\+):\).*/\1/;s|\\|/|g;s|^[^/]*|/enlistments|;G;s/\n//'

Explication (les étapes marquées d'un astérisque ( *`[]`** ) s'appliquent aux deux commandes) :

  • h - copier la ligne pour maintenir l'espace
  • s/^.*([[:digit:]]\+):// - supprimer la première partie de la ligne de l'original dans l'espace des motifs
  • x - échanger l'espace du motif et l'espace de maintien
  • s/^\(.*([[:digit:]]\+):\).*/\1/ - garder la première partie de la ligne de la copie (jeter la dernière partie)
  • s|\\|/|g - *[ `` ]** remplacer toutes les barres obliques inversées par des barres obliques (dans la version "diviser pour régner", seule la partie dans l'espace de motif - la première partie de la ligne - est concernée).
  • s|^[^/]*|/enlistments| - *[ `` ]** changer ce qui apparaît avant la première barre oblique en "/enlistments" - cela peut être rendu plus sélectif si nécessaire
  • G - ajoute une nouvelle ligne et le contenu de l'espace de maintien à la fin de l'espace de motif
  • s/\n// - supprime la nouvelle ligne intérieure

0voto

WingManEXE Points 611

Il y a deux faits qui, je pense, vous seront utiles :

  1. Par défaut, sed ne remplacera que la première occurrence d'une chaîne de caractères dans une ligne. Donc, étant donné la ligne suivante :

    foo foo

    La commande sed s/foo/bar/ aura pour résultat :

    bar foo
  2. Vous pouvez limiter une commande sed aux lignes correspondant à un motif spécifique. Si vous voulez effectuer la substitution ci-dessus uniquement sur les lignes contenant la chaîne "xyz", vous utiliserez une commande comme celle-ci :

    sed '/xyz/ s/foo/bar/'

Je pense que cela devrait vous aider à faire ce que vous voulez.

0voto

Hellonearthis Points 447

Vous pouvez essayer

sed -r 's/^[A-Z]:\\|\\/\//g' | sed 's/^/\/enlistments/'

Maintenant, cela nécessite bien sûr qu'il n'y ait pas de backslashes dans la partie après (25) : pour fonctionner. Mais comme je soupçonne que ce ne sera jamais le cas à cause de la structure des chemins unix, ce ne sera jamais le cas.

0voto

potong Points 176

Cela pourrait fonctionner pour vous (GNU sed) :

sed 's/([0-9]\+):/&\n/;h;s/\n.*//;y/\\/\//;s/[^/]*/\/enlistments/;G;s/\n.*\n//' file

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X