[Awk] Pb de substitution dans un fichier

Résolu
benjyd Messages postés 11 Statut Membre -  
[Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   -
Bonjour,
Voici mon soucis :
J'ai un fichier en entrée avec en tête de ligne 05 et en 31/32ème position 01.
Mon problème est de remplacer ce 05 pas 06
Par exemple :
05 1496321684067 1478963 478901
par 06 1496321684067 1478963 478901

Il me semble que c'est réalisable mais je ne sais plus si je peux utiliser awk seul ou si je dois le | avec un seb.
Merci d'avance pour vos réponses

Benjyd
--
_.-@ On est pas le meilleur quand on le croit mais quand on le sait...
sauf que je le sais pas encore!!! @-._

18 réponses

  1. renisaac Messages postés 2073 Statut Contributeur 139
     
    Salut Benjyd,

    je pense que
    sed -s /05/06/ fichier_entrée > fichier_sortie
    devrais faire l'affaire. Il te remplace a chaque ligne la première occurence de 05 par 06.

    Renisaac
    0
  2. benjyd Messages postés 11 Statut Membre
     
    J'avais essyé en l'ouvrant avec vi un
    :%s/^05/06/g mais le pb c'est que j'ai environ une ligne sur 2 qui est censée être affectée alors que là c'est toutes les lignes qui sont modifiées
    0
  3. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
     
    Salut,

    Il faudrait que tu précises si tu veux remplacer toutes les occurences commençant par "05" ou seulement celles commençant par "05" et se terminant par "01".
    0
  4. benjyd Messages postés 11 Statut Membre
     
    Oui en effet je me suis peut-être mal exprimé
    j'ai en effet la plupart de mes lignes qui commencent par 05 et je ne souhaite changer que celles qui commencent par 05 et qui on en 31 et 32 ème caractères 0 et 1 tout en sachant qu'entre le 05 et le 01 j'ai divers caractères mais que la position de 0/1 est toujours en 31 et 32 et que 01 ne se situe pas en fin de ligne mais en plein milieu!

    Encore désolé pour cet oubli et merci pour vos futures réponses.
    Cdlmt

    B1j
    0
  5. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  6. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    Salut benjyd,

    Pour çà, j'utiliserai Perl.

    $ cat data.txt
    03 1496321684067 1478963 478903 098678
    04 1496321684067 1478963 478901 098678
    05 1496321684067 1478963 478903 098678
    05 1496321684067 1478963 478901 098678
    05 1496321684067 1478963 478903 098678
    $ ./testpl.pl
    03 1496321684067 1478963 478903 098678
    04 1496321684067 1478963 478901 098678
    05 1496321684067 1478963 478903 098678
    06 1496321684067 1478963 478901 098678
    05 1496321684067 1478963 478903 098678
    

    Dans cet exemple, seule la 4ème ligne rempli les conditions. Le code de testpl.pl :

    #!/usr/bin/perl
    open(FICH, "data.txt");
    while (<FICH>) {
      if ( (/^05/) && (index($_,"01",29) eq "29") )  {
          $_ =~ s/^05/06/;
      }
      print "$_";
    }
    close(FICH);


    Dal
    0
  7. benjyd Messages postés 11 Statut Membre
     
    C'est bien ce que je pensais mais ne m'y connaissant pas en Perl je redoutais un peu d'en arriver là, je te remercie je teste de suite...
    0
    1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      J'ai édité mon post ci-dessus pour faire les tests en une ligne, avec un seul if. Celà rend le code plus compact sans trop nuire à la lisibilité.


      Dal
      0
  8. benjyd Messages postés 11 Statut Membre
     
    C'est nickel merci beaucoup, je pense que je vais me mettre un peu à Perl si vous avez du "Perl pour les nuls" ça peut m'intéresser!

    En tout cas merci et j'espère pouvoir un jour rendre la pareille

    B1j
    0
  9. benjyd Messages postés 11 Statut Membre
     
    Pour info, voici le code que j'ai utilisé :
    #!/usr/bin/perl
    open(FICH, "essai.txt");
    while (<FICH>) {
    if ( (/^05/) && (index($_,"01",32) eq "32") ) {
    $_ =~ s/^05/06/;
    }
    print "$_";
    }
    close(FICH);

    car en fait le 01 se trouvait en 33 et 34!!
    Encore merci...
    0
  10. benjyd Messages postés 11 Statut Membre
     
    par contre, est-ce normal que mes fichiers (avant et après) aient une taille différent (dans le script j'ai remplacé essai par avant et je lance conv.pl >apres.txt )?
    0
  11. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    Pour débuter avec Perl, ce lien est pas mal (en anglais) :

    http://www.troubleshooters.com/codecorn/littperl/

    Pour la différence de taille, je ne crois pas que ce soit normal... ton fichier avant.txt est bien un fichier ASCII Unix ? Lequel est plus petit ? La différence est de quel ordre ? Peux-tu les identifier avec un diff avant.txt apres.txt ?

    Dal
    0
    1. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
       
      A la ligne de commande, il y a aussi "perldoc".

      tape :

      perldoc perldoc
      perldoc perl


      pour apprendre à t'en servir.

      La base de données CPAN

      http://www.cpan.org/
      http://search.cpan.org/

      contient une ressource inépuisable de modules qui t'évitent d'avoir à réinventer la roue, pour faire tout un tas de choses. Tu les télécharges ou tu les installes directement à la ligne de commande, en mode intéractif avec :

      perl -MCPAN -e 'shell'
      install lemodulerecherché


      Celà télécharge le module et ses éventuelles dépendances, le teste et l'installe.


      Dal
      0
  12. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Salut,

    je propose une autre solution( j'ai pris le cas de Dal)
    #! /usr/bin/perl
    
    use warnings;
    
    while (<DATA>) {
      s/^05((?:.){28}01.+)/06$1/;
      print;
    }
    
    # j'utilse le handle DATA et je lit à partire de END
    # donc remplace DATA avec le handle de ton fichier
    
    # open(FICH, "data.txt") or die "Impossible ovrir fichir : $!\n";
    # et tu utilise while (<FICH>)
    __END__
    03 1496321684067 144478963 478903 098678
    04 1496321684067 147844963 478901 098678
    05 1496321684067 147896443 478903 098678
    05 1496321684067 147894463 478901 098678
    05 1496321684067 147896443 478903 098678
    

    Tu peut aussi utiliser la ligne de commande, pas besoin de script
    [lamitest@localhost corbeille]$ cat vider
    03 1496321684067 14478963 478903 098678
    04 1496321684067 14744963 478901 098678
    05 1496321684067 14789643 478903 018678
    05 1496321684067 14789463 478901 098678
    05 1496321684067 14789443 478903 098678
    [lamitest@localhost corbeille]$ perl -pi.orig -e 's/^05((?:.){28}01.+)/06$1/' vider
    [lamitest@localhost corbeille]$ cat vider
    03 1496321684067 14447963 478903 098678
    04 1496321684067 14744963 478901 098678
    05 1496321684067 14789443 478903 018678
    06 1496321684067 14784463 478901 098678
    05 1496321684067 14786443 478903 098678
    [lamitest@localhost corbeille]$ cat vider.orig
    03 1496321684067 14447863 478903 098678
    04 1496321684067 14784963 478901 098678
    05 1496321684067 14786443 478903 018678
    05 1496321684067 14789463 478901 098678
    05 1496321684067 14786443 478903 098678
    [lamitest@localhost corbeille]$
    0
  13. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Traduction de la documentation Perl http://perl.enstimac.fr/
    J'ai la même taille.
    [lamitest@localhost corbeille]$ diff -c vider vider.orig
    *** vider       2006-03-09 19:17:11.000000000 +0100
    --- vider.orig  2006-03-09 19:16:25.000000000 +0100
    ***************
    *** 1,5 ****
      03 1496321684067 144478963 478903 098678
      04 1496321684067 147844963 478901 098678
      05 1496321684067 147896443 478903 018678
    ! 06 1496321684067 147894463 478901 098678
      05 1496321684067 147896443 478903 098678
    --- 1,5 ----
      03 1496321684067 144478963 478903 098678
      04 1496321684067 147844963 478901 098678
      05 1496321684067 147896443 478903 018678
    ! 05 1496321684067 147894463 478901 098678
      05 1496321684067 147896443 478903 098678
    [lamitest@localhost corbeille]$ du -h vide*
    4,0K    vider
    4,0K    vider.orig
    [lamitest@localhost corbeille]$
    0
  14. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    Salut lami20j,

    elle est très cool ta regex 's/^05((?:.){28}01.+)/06$1/' ...

    Sur mes données elle marche avec 27 à la place de 28. Sinon, peux-tu l'expliquer (surtout la partie entre parenthèses) ?

    Est-elle compatible avec sed ?

    (auquel cas un sed -i ferait aussi l'affaire)

    Dal
    0
  15. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Et à la fin encore 2 version qui devront être plus rapides
    Chez toi c'est 27 puisque tu cherches les postions 30 et 31 pas 31 et 32
    while (<DATA>) {
      s/^05           # debut ligne 05
          (           # je capture le rest dans $1
            (?:       # paranthèse non capturante
                .     # n'importe quel caractère
            )         # donc je ne capture pas le resultat
                      # donc pas de consomation de texte
            {27}      # exact 27 fois : 05 + 27 =29
                      # donc après la pos 30 pour 0
                      # et 31 pour 1
                      # chez toi ça marche avec 27 puisque
                      # 0 est dans la postion 30 (pas 31)
            01        # 01 après 27+2 donc postiton 30 et 31
            .+        # au moins un caractère (donc 01 pas en fin de ligne)
            )         # fin de la capture $1
            /06$1/x;  # 06 concatené avec $1
                      # modificateur x pour commentaires dans regex
      print;
    }
    

    =============================================
    #! /usr/bin/perl
    
    use warnings;
    
    while (<DATA>) {
      s/^05           # debut ligne 05
          (           # je capture le rest dans $1
            (?:       # paranthèse non capturante
                .     # n'importe quel caractère
            )         # donc je ne capture pas le resultat
                      # donc pas de consomation de texte
            {27}      # exact 27 fois : 05 + 27 =29
                      # donc après la pos 30 pour 0
                      # et 31 pour 1
                      # j'ai toi ça marche avec 27 puisque
                      # 0 est dans la postion 30 (pas 31)
            (?=01)    # 01 après 27+2 donc postiton 30 et 31
                      # cette fois je fait un test avant
                      # qui veut dire que je regarde si après
                      # la positon 29 (ton cas) j'ai 0 suit de 1
                      # qui ne consomme pas de texte (plus rapide)
            .+        # au moins un caractère (donc 01 pas en fin de ligne)
            )         # fin de la capture $1
            /06$1/x;  # 06 concatené avec $1
                      # modificateur x pour commentaires dans regex
                      # la regex : s/^05((?:.){27}(?=01).+)/06$1/
      
      print;
    }
    ===========================================
    #! /usr/bin/perl
    
    use warnings;
    
    while (<DATA>) {
      # j'utilise seulement un test avant donc pas de capture en $1
      # et je remplace que 05
      # tout chaine qui commance avec 05
      # et après contient un chaine qui a dans les postions
      # 30 et 31, 0 suit de 1
      # pas en fin de ligne
      # je remplace 05 avec 06
      s/^05(?=(?:.){27}01.+)/06/;
      print;
    }
    
    0
  16. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re,

    Pour sed je ne crois pas. Je ne sais pas si le regex de sed utilise les test avant (?=...) ou les paranthèses non-capturante (?:...)

    Il faut demander jipicy, c'est lui mon préféré pour sed
    0
    1. jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 898
       
      Salut vous tous,

      Ben honnêtemment pour "sed" je sais pas et je crois pas que l'on puisse faire la même chose qu'en "perl", du moins avec "sed" tout seul (peut être que combiné avec "grep" et/ou "awk"...).

      En tout cas chapeau bas "lami20j" pour le script et les explications.

      J'ai encore jamais touché à "perl", mais je crois que je vais m'y mettre sérieusement ;-))

      PS. [Dal] => Ton tien était bien aussi ;-))
      0
  17. lami20j Messages postés 21506 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 571
     
    Re Dal,

    et pour pousser encore
    s/(?<=^0)5(?=(?:.){27}01.+)/6/;
    donc je fait un test arrière pour voir si j'ai 0 en début de ligne
    ensuite 5
    et le test avant expliqué dans le message précedent

    En ce cas tout reviens à remplace 5 avec 6

    Tant que la regex ne consomme pas de texte elle est rapide.
    0
  18. benjyd Messages postés 11 Statut Membre
     
    Merci pour votre aide...
    à la prochaine
    ps, j'aimerai avoir un avis sur mon forum si ça vous dérange pas :
    http://pasdepanique.misterforum.com
    il est tout récent donc personne dessus!
    0
  19. [Dal] Messages postés 6122 Date d'inscription   Statut Contributeur Dernière intervention   1 108
     
    Salut lami20j,

    Merci pour tes explications qui sont très claires. C'est impressionnant :)

    perldoc perlre

    semble confirmer que les expressions ayant une syntaxe d'une paire de parenthèses avec un point d'interrogation comme premier caractère entre les parenthèses correspondent à des fonctionnalités inexistantes dans les outils standard tels que awk (ou sed je présume). Il semblerait donc qu'on ne dispose pas de la même faculté de se promener dans la ligne en avant et en arrière pour y faire des tests sans capturer du texte sous sed, awk,...

    Dans le lien que tu as fourni, j'ai trouvé le PerlReTut, qui m'a l'air plus abordable que la page de manuel perlre :

    http://perl.enstimac.fr/DocFr/perlretut.html

    Dal
    0