IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

Remplacer un motif avec le contenu d'une variable via sed / awk


Sujet :

Shell et commandes GNU

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12
    Par défaut Remplacer un motif avec le contenu d'une variable via sed / awk
    Bonjour à tous.

    J'ai un problème plus que tordu...

    Voilà, j'ai un fichier fichier1 dont le contenu peut ressembler à ca :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    truc __var__ chose
     
          machin __var2__ bidule


    J'ai une variable var qui vaut "valeur1" et une variable var2 qui vaut "valeur2"


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var1=valeur1
    var2=valeur2

    L'idée, c'est donc de copier mon fichier1 vers fichier2 et de remplacer dans fichier2 __var__ par le contenu de $var et __var2__ par le contenu de $var2...


    Pour l'instant, j'arrive à faire ca :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    cat fichier1 | sed 's/__\(.*\)__/${\1}/g' >fichier2

    Ce qui donne un fichier2 qui ressemble à :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    truc ${var1} chose
     
          machin ${var2} bidule


    Le résultat attendu serait plutôt :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    truc valeur1 chose
     
          machin valeur2 bidule

    A préciser bien sûr que si j'ai, dans fichier1, le motif __supervariable__, il doit être remplacé par le contenu de $supervariable...


    La substitution des variables fonctionne avec le code suivant :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while read i; do
    echo $i | eval echo $(sed 's/__\(.*\)__/${\1}/g') >>fichier2
    done <fichier1

    Le souci, c'est que mon fichier2 s'en retrouve amputé de toutes les indentations... J'imagine que c'est le eval qui est responsable de cette amputation...

    Et du coup, là, je bloque... J'ai essayé avec awk et du gensub, mais je suis confronté aux mêmes problèmes finalement...


    Si quelqu'un a une idée, c'est avec grand plaisir que j'accueillerais sa solution


    Merci d'avance à tous.


    Deupac.

  2. #2
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 664
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut
    Bonjour deupac,

    Je ne comprend pas...
    tu connais la valeur de var1 du fichier_1 ?

    dans le pire des cas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sed 's/ancien/'"$nouvau"'/g' fichier
    ...
    ?
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    une réponse avec awk:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    awk -v v1=$var1 -v v2=$var2 '
    {
      gsub("__var__", v1)
      gsub("__var2__", v2)
      print
    }' fichier_1 > fichier_2
    L'explication du problème est un peu longue, mais elle est précise; elle permet d'aller rapidement vers une solution.

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12
    Par défaut
    Merci pour la solution, elle fonctionne.

    Le problème est que je ne connais pas forcément la totalité des motifs que contient fichier1.


    Pour être plus précis, je peux tout à fait avoir une collection de variables :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    var1=valeur1
    var2=valeur2
    var3=valeur3
    var4=valeur4

    Le fichier1 peut quant à lui contenir un, plusieurs ou aucun des motifs correspondant. Par exemple on peut avoir un fichier1 qui ressemble à ca :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bonjour __var__
            coucou __var4__

    ou bien qui ressemble à :


    ou encore à :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    hello __var__ et __var3__

    Le nombre de motifs n'est pas connu d'avance, et donc remplacer spécifiquement un motif par sa variable correspondante n'est pas possible.


    Merci !

  5. #5
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    En (très) rapide:

    Si tu as les variables var_1 à var_n dans ton script, c'est que tu connais le nombre max de changement à faire: n. Il faut alors demander les n changements dans le fichier à traiter. Si le motif n'est pas présent, c'est pas grave: aucun changement ne sera effectué.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    awk -v v_1=$var_1 -v v_2=$var_2 ... -v v_n=$var_n '
    {
      gsub("__var__", v_1)
      gsub("__var2__", v_2)
      ...
      gsub("__varn__", v_n)
      print
    }' fichier_1 > fichier_2

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12
    Par défaut
    Je suis bien d'accord avec toi et j'avais déjà pensé à cela, mais dans un souci d'évolutivité et de maintenabilité, si je rajoute une variable à ma collection de base, je préfèrerais ne pas avoir à l'ajouter en plus dans le awk, d'où mon besoin de substitution des variables de façon dynamique (je sais pas si je suis clair dans mes explications, si je ne le suis pas, il ne faut pas hésiter à me le signaler )

  7. #7
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 664
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut HS: langue
    "maintenabilité" ? oh, le barbarisme !
    ça existe ?

    entretien (à venir)
    ...
    ?
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12
    Par défaut
    http://fr.wikipedia.org/wiki/Maintenabilit%C3%A9

    Néologisme à la limite si tu veux, barbarisme, on va peut-être pas exagérer.

    Merci néanmoins pour ta constructive contribution.

  9. #9
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 664
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut HS : langue
    soit, c'est un terme entendu/convenu.
    (argh, je deteste les conventions, quand elles ne sont pas essentielles )

    reste qu'il est horrible !
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12
    Par défaut
    Reste qu'un terme qu'on trouve aussi dans le dictionnaire larousse ne peut selon moi plus vraiment être appelé "entendu / convenu". En fait ca existe, point barre.

    Par contre, puisque je n'avais pas voulu lancer un débat de langue vivante dans mon premier post, j'en reviens à l'essentiel...

    Bref, voilà une solution à mon problème pour ceux que cela pourrait intéresser...
    Je reprends depuis le début. Soit un fichier1 :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    bonjour __var__ coucou __var2__ et __var3__
     
            coucou __var2__
     
    salut __var3__

    On se moque donc de savoir si les variables $var, $var2, $var3 etc sont valorisées..., si elles sont vides, alors les motifs correspondants seront remplacés par du vide.


    Le code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while read line; do
    echo "$line" | eval echo $(awk '{for (NUM_CHAMP = 1; NUM_CHAMP <= NF ; NUM_CHAMP++) {if ($NUM_CHAMP ~ /^__/ && $NUM_CHAMP ~ /__$/) ; { gsub(/^__/,"${",$NUM_CHAMP) ; gsub(/__$/,"}",$NUM_CHAMP) }  }  print }')
    done < fichier1


    Le résultat (en admettant que $var, $var2 et $var3 soient respectivement valorisées à valeur, valeur2 et valeur3) :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    bonjour valeur coucou valeur2 et valeur3
     
    coucou valeur2
     
    salut valeur3


    Autre résultat, en admettant que seules $var et $var2 soient valorisées :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    bonjour valeur coucou valeur2 et
     
    coucou valeur2
     
    salut

    Les occurrences de __var3__ sont remplacées par du vide.


    Le seul truc qui ne correspond pas à ce que je veux, c'est que je perd les tabulations. Je n'ai pas encore trouvé de moyen de les conserver, mais je garde espoir.


    Merci pour vos contributions.

    Deupac.

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Septembre 2009
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12
    Par défaut
    Les réponses ne se bousculent pas, aussi j'imagine que le post n'intéresse pas grand monde, cependant, je vais quand même poster la solution que j'ai adopté (qui a vachement moins la classe qu'une paire de sed et de awk, mais tant pis )

    Le awk que je proposais juste avant me posait un problème : si le motif __*__ n'était pas suivi d'un caractère vide, ca ne fonctionnait pas.


    Soit le fichier "fichier" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    bonjour __var_a_la_con__ coucou __var2__ et __var3__ et surtout __var__/__var2__
     
            hello __var__ hello


    Le script complet qui fait la transformation est comme ca :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #!/bin/bash
     
    # en vrai ces variables seront pas déclarées ici mais c'est pour l'exemple
    var=valeur1
    var2=valeur2
    var3=valeur3
    var_a_la_con=valeur_toute_moisie
     
    rm -f autrefichier &>/dev/null
     
    cp fichier autrefichier
     
    for i in $(grep -o __[A-Za-z0-9_]*__ fichier | sed 's/__\([A-Za-z0-9_]*\)__/\1/g')
       do
       lavar=$i
       sed -i 's/__'"$i"'__/'"${!lavar}"'/g' autrefichier    
    done



    Explications :

    le cp du fichier source vers le fichier cible permet de garder l'indentation si chère à mes yeux.

    dans le for : le grep -o récupère et n'affiche que les motifs __*__
    dans le for : le sed dégage les __ du résultat renvoyé par le grep -o

    lavar stocke le nom du motif courant amputé de ses __

    le sed : remplace le motif complet courant par le contenu de la variable qui porte le même nom que le motif sans __, ceci via référence indirecte, puisque si var=coucou et que coucou=bonjour, alors ${!var} = bonjour. le sed modifie bien entendu directement le fichier cible.


    Le fichier "autrefichier" resultat :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    bonjour valeur_toute_moisie coucou valeur2 et valeur3 et surtout valeur1/valeur2
    
            hello valeur1 hello
    

    J'en profite pour passer le post en résolu. Merci à jmelyn, seul et unique contributeur à mon problème


    Deupac.

  12. #12
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    Bonjour Deupac,

    Tout d'abord je voudrais préciser ceci: ce n'est pas parce que je ne mets pas de réponse que je ne réfléchis pas au problème. Hier j'ai passé un moment sans solution correcte. Et puis au travail ce n'est pas ma première priorité, même si je m'améliore très nettement en lisant les problèmes, en cherchant des solutions et en découvrant les solutions des autres.

    Cet aprèm j'ai trouvé quelque chose qui pourrait t'intéresser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/bin/bash
     
    unset var
    var[1]=valeur_1
    var[2]=valeur_2
    var[3]=valeur_3
    ...
     
    awk -v list="${var[*]}" '
    BEGIN {size=split(list, v)}
    {
      gsub("__var__", v[1])
      for (i=2; i <= size; i++)
      {
        gsub("__var" i "__", v[i])
      }
      print
    }' file_in > file_out
    Attention, cette solution ne fonctionne que si les valeurs valeur_1, valeur_2..., valeur_n ne contiennent pas d'espace.

  13. #13
    Membre émérite Avatar de jmelyn
    Homme Profil pro
    Administrateur systèmes et réseaux
    Inscrit en
    Septembre 2007
    Messages
    703
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France

    Informations professionnelles :
    Activité : Administrateur systèmes et réseaux

    Informations forums :
    Inscription : Septembre 2007
    Messages : 703
    Par défaut
    Alors, petite restriction précédente enlevée: il peut maintenant y avoir des espaces dans les variables var[i]:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    #!/bin/bash
    
    unset var
    var[1]="valeur 1"
    var[2]="valeur 2"
    var[3]="valeur 3"
    ...
    sep="#"
    IFS=$sep
    awk -v list="${var[*]}" -v s="$sep" '
    BEGIN {size=split(list, v, s)}
    {
      gsub("__var__", v[1])
      for (i=2; i <= size; i++)
      {
        gsub("__var" i "__", v[i])
      }
      print
    }' file_in > file_out
    Les modifications par rapport à mon précédent post son en bleu. Le truc ici est la valeur "${var[*]}": c'est la liste des valeurs du tableau var séparées par le premier caractère de IFS, parce que j'ai utilisé les doubles-quotes. Fallait le savoir!

    Bien sûr, je suppose que le caractère '#' n'apparait pas dans les valeurs de var puisque c'est un séparateur. Mais c'est maintenant paramétrable, on peut mettre ce qu'on veut.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 19/04/2014, 13h26
  2. Renommer fichier PHP avec le contenu d'une VARIABLE
    Par DezMax dans le forum Langage
    Réponses: 2
    Dernier message: 31/12/2012, 12h06
  3. Réponses: 7
    Dernier message: 02/11/2009, 14h40
  4. [PHP 4] Affichage d'une image avec chemin contenu dans une variable
    Par terrysharp dans le forum Langage
    Réponses: 1
    Dernier message: 16/07/2009, 14h54
  5. executer une requete avec le contenu d'une variable
    Par giloo(94) dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 03/02/2007, 01h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo