[Awk] Pb de substitution dans un fichier

Résolu/Fermé
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009 - 8 mars 2006 à 11:57
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 - 10 mars 2006 à 10:52
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
A voir également:

18 réponses

renisaac Messages postés 2043 Date d'inscription dimanche 22 août 2004 Statut Contributeur Dernière intervention 15 mai 2021 138
8 mars 2006 à 12:10
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
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009
8 mars 2006 à 14:08
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
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 895
9 mars 2006 à 12:19
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
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009
9 mars 2006 à 13:59
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

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
9 mars 2006 à 14:38
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
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009
9 mars 2006 à 14:44
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
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
9 mars 2006 à 14:47
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
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009
9 mars 2006 à 14:54
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
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009
9 mars 2006 à 14:56
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
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009
9 mars 2006 à 15:13
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
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
9 mars 2006 à 18:18
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
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
9 mars 2006 à 18:37
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
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
9 mars 2006 à 19:08
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
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
9 mars 2006 à 19:35
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
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
9 mars 2006 à 19:57
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
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
9 mars 2006 à 20:32
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
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
9 mars 2006 à 20:55
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
jipicy Messages postés 40842 Date d'inscription jeudi 28 août 2003 Statut Modérateur Dernière intervention 10 août 2020 4 895
9 mars 2006 à 23:02
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
lami20j Messages postés 21331 Date d'inscription jeudi 4 novembre 2004 Statut Modérateur, Contributeur sécurité Dernière intervention 30 octobre 2019 3 567
9 mars 2006 à 22:34
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
benjyd Messages postés 11 Date d'inscription dimanche 14 septembre 2003 Statut Membre Dernière intervention 10 janvier 2009
10 mars 2006 à 10:12
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
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
10 mars 2006 à 10:52
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