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

Langage Perl Discussion :

Modification de lignes dans un fichier...


Sujet :

Langage Perl

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 52
    Points : 22
    Points
    22
    Par défaut Modification de lignes dans un fichier...
    Bonsoir,

    Je voulais faire un script pour modifier des lignes dans un fichier, mais le script n'a pas l'air de fonctionner, le voici :

    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
    #!/usr/bin/perl
    $file = "test.conf";
    	$old = $file;
        $new = "$file.tmp.$$";
        $bak = "$file.orig";
        open(OLD, "< $old")         or die "can't open $old: $!";
        open(NEW, "> $new")         or die "can't open $new: $!";
     
        while (<OLD>) {
            s/\btest\b/megacool/i;
            (print NEW $_)          or die "can't write to $new: $!";
        }
        close(OLD)                  or die "can't close $old: $!";
        close(NEW)                  or die "can't close $new: $!";
        rename($old, $bak)          or die "can't rename $old to $bak: $!";
        rename($new, $old)          or die "can't rename $new to $old: $!";
    Dans ce cas il modifie bien le fichier test.conf, en changeant test par megacool...

    Pour le moment tout va bien,
    Mais voici ce que j'aimerais vraiment faire.

    Je souhaiterais modifier les lignes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #gamepanel2
    <Location >
            Order allow,deny
            Deny from all
    </Location>
    Par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #gamepanel2
    <Location >
            Order allow,deny
            Allow from all
    </Location>
    Donc voici le nouveau code :
    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
     
    #!/usr/bin/perl
    $file = "test.conf";
    	$old = $file;
        $new = "$file.tmp.$$";
        $bak = "$file.orig";
        open(OLD, "< $old")         or die "can't open $old: $!";
        open(NEW, "> $new")         or die "can't open $new: $!";
        # Correction des fautes de frappe, en préservant les majuscules
        while (<OLD>) {
            s/\b#gamepanel2
    <Location >
            Order allow,deny
            Deny from all\b/#gamepanel2
    <Location >
            Order allow,deny
            Deny from all/i;
            (print NEW $_)          or die "can't write to $new: $!";
        }
        close(OLD)                  or die "can't close $old: $!";
        close(NEW)                  or die "can't close $new: $!";
        rename($old, $bak)          or die "can't rename $old to $bak: $!";
        rename($new, $old)          or die "can't rename $new to $old: $!";
    Mais dûes à des erreurs, cela ne modifie pas le fichier...
    Serait-ce à cause des caractéres spéciaux (<, >, #, /...) ?

    Malgrés toutes les F.A.Q et documentations, je n'ai rien trouvé pour m'aider

    Pouvez-vous m'aider ?

    Merci d'avance

  2. #2
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    C'est tout à fait normal : tu lis ligne par ligne...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
        while (<OLD>) {
            s/\btest\b/megacool/i;
            (print NEW $_)          or die "can't write to $new: $!";
        }
    Là tu lis une ligne de OLD, tu changes un mot dedans, puis tu écris la ligne modifiée dans NEW.
    Dans le second cas, tu essaies de modifier plusieurs lignes à la fois de ton fichier alors que tu le lis ligne à ligne....

    Pour régler le problème, tu as deux solutions : soit tu lis l'intégralité du fichier dans une variable, tu effectue la modification souhaitée sur cette variable et tu la récris dans NEW, soit tu lis ligne par ligne et tu "prend note" du fait que tu es entré dans le secteur qui t'intéressait, tu modifie la ligne que tu veux modifier (puisqu'en réalité tu ne modifies qu'une ligne mais dans un contexte bien particulier) si tu es bien dans ce secteur, et tu "prend note" du fait que tu es ressorti du secteur intéressant. (le "prend note" correspond à une variable booléenne qui t'indique si tu te trouve dans le secteur intéressant et donc si tu peux effectuer ta modification).

    La première solution est plus simple, mais dangereuse si tu crains d'avoir affaire à des fichiers vraiment gros (a priori pour la conf d'Apache ça devrait aller), la seconde est plus performante, plus sûre et plus formatrice : c'est un type de situation que tu retrouves souvent, et parfois la seconde solution est beaucoup plus adaptée.

    --
    Jedaï

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 52
    Points : 22
    Points
    22
    Par défaut
    Merci,

    Mais comment je fais tout cela ?
    Vous n'auriez pas des exemples ?

    Désolé, mais je commences à peine le PERL

  4. #4
    Expert confirmé
    Avatar de GLDavid
    Homme Profil pro
    Service Delivery Manager
    Inscrit en
    Janvier 2003
    Messages
    2 852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Service Delivery Manager
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Janvier 2003
    Messages : 2 852
    Points : 4 759
    Points
    4 759
    Par défaut
    Salut

    Pourquoi pas lire mes cours de Perl (la 3ème partie est une initiation aux fichiers) et lire la FAQ ?
    Cela t'affranchirait au moins des bases de Perl et je suis qu'après, ce sera plus lumineux, même les explications de Maître Jedai :p

    @++
    GLDavid
    Consultez la FAQ Perl ainsi que mes cours de Perl.
    N'oubliez pas les balises code ni le tag

    Je ne répond à aucune question technique par MP.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 52
    Points : 22
    Points
    22
    Par défaut
    Et bien, j'ai déjà lu tout ceci

    Serais-je aveugle ?

    Dans tous les cas je vais essayer avec des \n ...

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 52
    Points : 22
    Points
    22
    Par défaut
    Même avec les \n , cela ne marche pas

  7. #7
    Expert confirmé
    Avatar de GLDavid
    Homme Profil pro
    Service Delivery Manager
    Inscrit en
    Janvier 2003
    Messages
    2 852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Service Delivery Manager
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Janvier 2003
    Messages : 2 852
    Points : 4 759
    Points
    4 759
    Par défaut
    Salut

    Ton problème est plus complexe. Ce que Jedai a voulu dire c'est que mettre toute ta chaîne avec des retour chariot serait trop complexe à gérer.
    Je te propose cette solution, un peu gourmande en mémoire (du moins si le fichier est important) mais qui devrait fonctionner.
    L'idée est simple. Tu veux modifier ces lignes suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #gamepanel2
    <Location >
            Order allow,deny
            Deny from all
    </Location>
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    #gamepanel2
    <Location >
            Order allow,deny
            Allow from all
    </Location>
    Ce que nous allons faire d'abord, c'est stocker chaque ligne du fichier dans un tableau avec push et la variable défaut $_ :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    my @tablo = ();
    open(FILE, "< $file") or die "$!\n";
    while(<FILE>){
    push(@tablo, $_);
    }
    Ensuite, nous allons parcourir le tableau ainsi créé pour chercher ce motif #gamepanel2 et modifier 3 lignes plus loin le Deny en Allow :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    for(my $i=0; $i<@tablo; $i++){
    my $ligne = $tablo[$i];
    if($ligne=~/#gamepanel2 /){
    $tablo[$i+3]=~s/Deny/Allow/
    }
    }
    Ensuite, il te suffira d'écrire chaque élément du tableau @tablo dans un nouveau fichier, d'effacer l'ancien et de renommer ce nouveau fichier avec le nom de l'ancien ficheir.
    Et voilà, le tour devrait être joué !

    @++
    GLDavid
    Consultez la FAQ Perl ainsi que mes cours de Perl.
    N'oubliez pas les balises code ni le tag

    Je ne répond à aucune question technique par MP.

  8. #8
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 52
    Points : 22
    Points
    22
    Par défaut
    J'ai rien dis

    Je n'avais pas fait ce que vous avez dis apres ton code.......

  9. #9
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 52
    Points : 22
    Points
    22
    Par défaut
    Ensuite, il te suffira d'écrire chaque élément du tableau @tablo dans un nouveau fichier, d'effacer l'ancien et de renommer ce nouveau fichier avec le nom de l'ancien ficheir.
    Mais comment faire tout cela ?

  10. #10
    Expert confirmé
    Avatar de GLDavid
    Homme Profil pro
    Service Delivery Manager
    Inscrit en
    Janvier 2003
    Messages
    2 852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Service Delivery Manager
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Janvier 2003
    Messages : 2 852
    Points : 4 759
    Points
    4 759
    Par défaut
    Salut

    Ok, essaies de bien lire la FAQ, y a pas mal de choses intéressantes dessus.
    Pour faire l'enchaînement que je t'ai indiqué, tu peux le faire séquentiellement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    unlink("old.txt");
    rename("new.txt", "old.txt");
    unlink("new.txt");
    Mieux encore ! On peut tout écrire en 1 ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    unlink("old.txt") and rename("new.txt", "old.txt") and unlink("new.txt");
    @++
    GLDavid
    Consultez la FAQ Perl ainsi que mes cours de Perl.
    N'oubliez pas les balises code ni le tag

    Je ne répond à aucune question technique par MP.

  11. #11
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Comprends-tu ce qu'a fait GLDavid ?
    Si tu ne comprends pas, continue à poser des questions, ça te permettra d'adapter la solution plus tard.

    Sinon, une solution peut-être plus limpide :
    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
    25
    26
    27
    28
    29
    30
    31
     
    #!/usr/bin/perl
    use strict; use warnings;
     
    my $file = "test.conf";
    my $old = $file;
    my $new = "$file.tmp.$$";
    my $bak = "$file.orig";
    open(OLD, "< $old")         or die "can't open $old: $!";
    open(NEW, "> $new")         or die "can't open $new: $!";
     
    my $content;
    #on met la totalité du vieux fichier dans $content
    {
      local $/;
      $content = <OLD>;
    }
     
    #on effectue la substitution :
    $content =~ s{#gamepanel2\s+<Location >\s+Order allow,deny\s+Deny from all\s+</Location>}
                  {#gamepanel2\n<Location >\n\tOrder allow,deny\n\tAllow from all\n</Location>};
     
    #on écrit le contenu modifié dans le nouveau fichier
    print NEW $content          or die "can't write to $new: $!";
     
    close(OLD)                  or die "can't close $old: $!";
    close(NEW)                  or die "can't close $new: $!";
     
    #on renomme l'ancien fichier en .orig, et on met le nouveau à la place
    rename($old, $bak)          or die "can't rename $old to $bak: $!";
    rename($new, $old)          or die "can't rename $new to $old: $!";
    Dans la substitution ci-dessus, \s+ signifie un ou plusieurs caractère d'espacement (ce qui comprend l'espace, le retour à la ligne, la tabulation, ...), \n veut dire passage à la ligne, et \t veut dire tabulation.
    Est-ce que c'est plus clair ?

    --
    Jedaï

  12. #12
    Membre à l'essai
    Profil pro
    Inscrit en
    Août 2005
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 52
    Points : 22
    Points
    22
    Par défaut
    Je comprends un peu ce qu'a fait GLDavid.

    J'étais en train de trouver une autre solution, certes plus longue et plus compliquée, alternance PHP<>PERL , comme je sais modifier des lignes en PHP...

    Je viens de tester votre script, Jedai, et il marche à la perfection

    Merci.

Discussions similaires

  1. [sed] Modification d'une ligne dans un fichier
    Par tiresias54 dans le forum Shell et commandes GNU
    Réponses: 15
    Dernier message: 07/04/2015, 16h35
  2. Réponses: 3
    Dernier message: 08/08/2009, 18h05
  3. [FSO] Effacer une ligne dans un fichier
    Par Johnbob dans le forum ASP
    Réponses: 4
    Dernier message: 30/05/2007, 16h23
  4. Réponses: 2
    Dernier message: 02/03/2004, 19h38
  5. Supprimer une ligne dans un fichier
    Par sbeu dans le forum Langage
    Réponses: 3
    Dernier message: 13/05/2003, 10h30

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