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 :

Récupérer un bloc de lignes dans un fichier en modifiant certaines valeurs puis le réinsérer dans le fichier


Sujet :

Shell et commandes GNU

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 45
    Points : 22
    Points
    22
    Par défaut Récupérer un bloc de lignes dans un fichier en modifiant certaines valeurs puis le réinsérer dans le fichier
    Bonjour,

    Sous ce titre long et pas forcément explicite, je cherche à récupérer un bloc de ligne spécifique dans un fichier qui ne peut être identifié que par une seule ligne.
    Une fois cette ligne identifiée, je souhaite afficher les 3 lignes qui se trouvent au-dessus. (Cela peut être fait facilement avec un grep -B 3 maligne monfichier)

    La où ça se corse, c'est que je dois remplacer 3 valeurs sur ces 3 lignes en me basant sur 2 Regex (Adresse MAC + Nom du serveur) puis réintégrer ces modifications dans le fichier en remplaçant cette ensemble de ligne dans le fichier. Cela doit être un remplacement en lieu et place de l'ancien.
    Le tout doit tenir si possible sur une seule ligne

    Voici un extrait de mon fichier :

    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
    20
    21
    22
    23
    host SRV00844 {
                  option host-name "SRV00864.mydomain.fr";
                  hardware ethernet 00:50:56:9b:44:94;
                  fixed-address 223.129.130.16;
                   }
     
    host SRV00847 {
                  option host-name "SRV00865.mydomain.fr";
                  hardware ethernet 00:50:56:9b:36:8e;
                  fixed-address 223.129.130.17;
                   }
     
    host SRV00868 {
                  option host-name "SRV00438.mydomain.fr";
                  hardware ethernet 00:50:56:9b:36:8e;
                  fixed-address 223.129.130.18;
                   }
     
    host SRV00898 {
                  option host-name "SRV00852.mydomain.fr";
                  hardware ethernet 00:50:56:9b:54:2a;
                  fixed-address 223.129.130.19;
                   }
    Exemple :
    Sur ce bloc de ligne, je veux remplacer le nom du serveur et l'adresse MAC.
    host SRV00844 {
    option host-name "SRV00864.mydomain.fr";
    hardware ethernet 00:50:56:9b:44:94;
    fixed-address 223.129.130.16;
    }
    J'utilise la ligne 223.129.130.16; comme point de repère pour pouvoir modifier mes valeurs. Je n'ai aucune idée des valeurs qui seront affichées sur les 3 lignes du dessus.
    Tout ce que je sais, c'est que je dois remplacer ces valeurs (Serveur + Adresse MAC) avec d'autres que je connais en utilisant les regex suivants:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Serveur : SRV00[1-9]\d{2}
    Adresse MAC : ([0-9a-f]{2}:){5}([0-9a-f]{2})
    J'ai tenté différents essais avec le SED mais je n'ai pas réussi...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Essai 1 (Impossible de récupérer les 3 dernières lignes sous SED)
    sed -i 's/*\n{3}223.129.130.16;/host SRV00417 {\n              option host-name "SRV00417.mydomain.fr";\n              hardware ethernet 00:50:56:9b:45:29;\n              fixed-address 223.129.130.16;/g' MYFILE
     
    Essai 2 (Remplace tous les serveurs et les adresses MAC par ceux que j'ai défini)
    tac MYFILE | sed -ne '/223.129.130.16;/,+3p' | sed -i 's/\([0-9a-f]\{2\}:\)\{5\}\([0-9a-f]\{2\}\)/00:50:56:9b:45:29/; s/SRV00[1-9][0-9]\{2\}/SRV00417/g' MYFILE
    Est-ce qu'un esprit avisé pourrait m'éclairer sur cette requête ? SED est t'il la bonne approche pour ce cas de figure ?

    En vous remerciant d'avance.

  2. #2
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    tac | sed est une bonne approche, par contre il faut oublier l'édition inplace à mon avis, il y a peut-être moyen mais le gain est probablement moindre que la complexité de mise en oeuvre (je suis pas un as avec sed, mais avec awk c'est le cas)

    si on part sur ton idée de tac le fichier (le code est déplié pour la lisibilité) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ tac fichier | sed -r '
    /[^0-9]223\.129\.130\.16[^0-9]/ {
       n;
       s/([0-9a-f]{2}:){5}([0-9a-f]{2})/TOTO/;
       n;
       s/SRV00[1-9][0-9]{2}/POUET/;
       n;
       s/SRV00[1-9][0-9]{2}/POUET/
    }' | tac
    il suffit d'une redirection qui va bien derrière pour enregistrer le nouveau fichier (et pour info l'édition en ligne fait rigoureusement la même chose de toutes façon, c'est juste transparent pour l'utilisateur)

    j'ai une affection pour awk :
    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
    20
    $ awk -vIP="223.129.130.16" -vSERVNAME="POUET" -vMACADDR="TOTO" '
    {
       # on met tout le fichier en memoire, dans un tableau
       ligne[NR-1]=$0;
    }
     
    $0 ~ "[^0-9]" IP "[^0-9]" { # on match si IP _exacte_
       # on effectue les modifications sur les lignes precedentes
       gsub(/SRV00[1-9][0-9]{2}/, SERVNAME, ligne[NR-4]);
       gsub(/SRV00[1-9][0-9]{2}/, SERVNAME, ligne[NR-3]);
       gsub(/([0-9a-f]{2}:){5}([0-9a-f]{2})/, MACADDR, ligne[NR-2]);
    }
     
    END {
       # a la fin on afficher toutes les lignes du fichier
       for (i = 0; i < NR; i++) {
          printf("%s\n", ligne[i]);
       }
    }
    ' fichier
    ça passe tel quel dans la console, au besoin on pourra aussi mettre le script dans un fichier, l'invocation devient un peu plus lisible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -f script.awk -vIP="223.129.130.16" -vSERVNAME="POUET" -vMACADDR="TOTO" fichier
    pareil, une redirection dans un nouveau fichier, suivi d'un remplacement à coup de mv et on en parle plus

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 552
    Points : 19 392
    Points
    19 392
    Par défaut
    Bonjour,

    c'est une procédure qu'on voit souvent :
    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
    20
    21
    22
    23
    24
    sed '/^host/{:a;/}$/!{N;ba};/223\.129\.130\.16/{s/SRV00[1-9]\{3\}/SERVEUR/g;s/\([0-9a-f]\{2\}:\)\{5\}[0-9a-f]\{2\}/MAC/}}' "$tonFichier"
    host SERVEUR {
                  option host-name "SERVEUR.mydomain.fr";
                  hardware ethernet MAC;
                  fixed-address 223.129.130.16;
                   }
     
    host SRV00847 {
                  option host-name "SRV00865.mydomain.fr";
                  hardware ethernet 00:50:56:9b:36:8e;
                  fixed-address 223.129.130.17;
                   }
     
    host SRV00868 {
                  option host-name "SRV00438.mydomain.fr";
                  hardware ethernet 00:50:56:9b:36:8e;
                  fixed-address 223.129.130.18;
                   }
     
    host SRV00898 {
                  option host-name "SRV00852.mydomain.fr";
                  hardware ethernet 00:50:56:9b:54:2a;
                  fixed-address 223.129.130.19;
                   }
    je laisse le soin à Sperafico de nous expliquer la commande sed.
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Mai 2010
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2010
    Messages : 45
    Points : 22
    Points
    22
    Par défaut
    Merci à vous deux pour vos retours.
    La méthode SED de N_BaH est vraiment puissante et diablement efficace.

    Tu as pris comme point de référence host et tu lis chaque ligne jusqu’à trouver l'IP recherché.
    J'avoue que malgré le man, la section de code en bleu n'est pas facile à déchiffrer...

    /^host/{:a;/}$/!{N;ba};/223\.129\.130\.16/

    Pourrais-tu m'éclairer un peu plus ?

  5. #5
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    • /^host/{...} est un bloc d'instructions conditionné par la regex
    • :a est un label, une étiquette
    • /}$/ !{...} la tournure la moins intuitive à mon sens, revient à "tant qu'on ne match pas on exécute le bloc d'instructions", en clair on cherche l'accolade fermante du bloc host {...}
    • N;ba on rajoute la ligne dans le pattern space, puis goto a

    donc on match le début /^host/, tant qu'on ne match pas la fin /}$/ on agrandi le pattern space, sur lequel on aura plus qu'à effectuer les substitutions

  6. #6
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 286
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 286
    Points : 12 742
    Points
    12 742
    Par défaut
    Bonjour,

    Pour le fun, une autre version en awk:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk -vIP=223.129.130.17 -vSV=SERVNAME -vMC=MAC 'BEGIN{RS="}"} {A=$0"}"} A ~ IP {sub(/SRV00[0-9]+\./, SV".",A);sub(/([0-9a-f]+:)+[0-9a-f]+/,MC,A)}/host/{print A}' fichier
    Cordialement.

Discussions similaires

  1. Réponses: 0
    Dernier message: 29/01/2012, 15h15
  2. [DOM] Modifier la valeur d'un noeud dans un fichier XML
    Par rob2-9 dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 25/08/2008, 20h31
  3. Réponses: 6
    Dernier message: 15/02/2008, 11h10
  4. Récupérer dans matrice indice d'un certaine valeur
    Par hollowdeadoss dans le forum MATLAB
    Réponses: 10
    Dernier message: 24/05/2007, 15h12
  5. Réponses: 9
    Dernier message: 04/05/2006, 17h33

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