Forum Programmation.shell Parcourir et modifier un fichier

Posté par  .
Étiquettes : aucune
0
3
mai
2006
Bonjour,

je dois modifier des fichiers se trouvant dans des répertoires en supprimant tout ce qui est entre *{ et }*.
J'ai essayé différente solution mais j'ai plusieurs problèmes en faisant mon script :
les fichiers ont la forme pour mettre des commentaires
*************************
*
* ceci est le fichier *
* qui n'a pas de sens *
*************************
int void () ...

1°) Je parcours les fichiers et je réécrit tout dans un autre fichier avec un while read mais dans les fichiers il y a des * et ceci sont remplacés par les fichiers du path courant (surtout les ceux de fin de ligne) et à chaque fois que je vois *{ je n'écris plus dans le ficher temporaire.
A cause des * de fin de ligne je modifie le fichier initial de manière érroné et les quotes engendre une incomprehension.

Comment faire pour résoudre ce problème ? Y a t'il une solution simple et efficace ?

Merci d'avance
  • # Heu précise exactement ce que tu veux...

    Posté par  (site web personnel) . Évalué à 2.

    Bon en considérant que ton fichier d'exemple (test) soit ça :
    *************************
    * *
    * ceci est le fichier *
    *{qui n'a pas de sens}*
    *************************
    Toin fichier résultat :
    *************************
    * *
    * ceci est le fichier *
    *{}*
    *************************
    Une commande qui te fait ça :
    cat test | perl -ne 's/\*{[^}]*}\*/*{}*/; print $_'

    les \* c'est un backquote des * qui ont un sens de répétition infinie du terme prédédent dans le premier member d'une expression régulière.
    Exemple : [^}]*
    On répète autant de fois qu'on veux le motif : ^} soit tout sauf une accolade fermante.

    Donc \*{[^}]*}\* marche pour tout motif *{n'importe quo ici}*
    Après ça le remplace et ça affiche le résultat dans tout les cas.

    Vala en espérant que ça soit suffisant...
    • [^] # Re: Heu précise exactement ce que tu veux...

      Posté par  . Évalué à 1.

      Salut,

      merci pour ta réponse mais ce n'est pas tout à fait cela.
      fichier test en entrée :
      *********************************
      * ceci est le fichier qui fait rien*
      *********************************
      function int ()

      *{ ceci ne sert à rien et n'a
      * pas de sens et doit être enlever
      *}
      la suite du code
      encore
      *{ ceci ne sert à rien et n'a
      * pas de sens et doit être enlever*}

      fichier attendu :
      *********************************
      * ceci est le fichier qui fait rien*
      *********************************
      function int ()
      la suite du code
      encore

      Voila ce qui ce que j'attend.
      Je pensais faire avec un cat ou un awk (bof?) et une expression régulière mais je n'y suis pas arrivé.
      J'ai testé ce que tu a écrit mais cela ne fait rien.
      N'étant pas doué pour les cat j'avais choisit de passer par un script lisant ligne par ligne le fichier mais le read et les astérisques ne font pas ensemble ainsi que les quotes. Les astérisques sont remplacés par les fichiers du répertoire!

      J'espère avoir été plus clair cette fois, et merci d'avance pour toute l'aide possible.
      c
      • [^] # Re: Heu précise exactement ce que tu veux...

        Posté par  . Évalué à 1.

        En fait je pensais faire un sed et non un cat et je vais repartir sur cette voie pour l'instant vu qu'avec read cela ne donne rien. Va falloir que je trouve une expression régulière correcte.
        Merci
        c
        • [^] # Re: Heu précise exactement ce que tu veux...

          Posté par  . Évalué à 1.

          Bonsoir,

          Voici une solution au problème :
          sed '/\*{/,/\*}/ s/.*//g' nom_fichier | grep -v '^$' >nouveau_fichier

          Explications :
          - /\*{/,/\*}/ : la recherche s'effectue entre les 2 expressions régulières (entre *{ et *}
          - s/.*//g : tout est alors supprimé (remplacé par rien)
          - grep -v '^$' : les lignes vides sont supprimées

          Evident, mais ça m'a demandé pas mal de temps...
          • [^] # Re: Heu précise exactement ce que tu veux...

            Posté par  . Évalué à 1.

            Bonjour,

            merci pour cette proposition mais je n'ai pas été assez clair sur mon problème et j'en suis désolé.
            En fait j'avais commencé par faire un petit script, vu les besoins que j'avais, lisant ligne par ligne mais cela n'a pas fonctionner et je suis dans une impasse dans cette voie là à cause des tests d'égalités (une ligne contient "*{" pas forcement au début), je ne connais pas de matches en shell et surtout le read ligne à ligne engendrait des incohérences sur le passage des astérisque.(remplacement de la dernière astérisque par tout ce qu'il y a dans le path courant!!)
            Donc je me suis dit qu'il fallait que je trouve une expression régulière permetttant de faire cela mais il me semble que c'est impossible et ce malgré le temps que j'y ai passé!
            J'ai trouvé un expression régulière similaire à la tienne mais elle est trop efficace.
            Je veux dire par la qu'elle efface - celle que j'avais fait aussi - tout ce qui se trouve en *{ et }* alors qu'il faudrait qu'elle efface les lignes commencant par *{ et contenant *} et toutes celles entre qui commence pas *
            En gros
            titi
            *loulou
            {* blablaba
            * bloblo
            blibli
            *toto
            *}
            tata

            doit me rendre :

            titi
            *loulou
            blibli
            tata

            Voila j'aurais du mettre un exemple plus parlant encore désolé. Je continue à chercher mais c'est pas gagner. Si quelqu'un a une idée que ce soit à l'aide d'une expression régulière avec un awk (que je connais pas) ou un sed ou un moyen que le read ne transforme pas les * de fin de ligne je pourrais réutiliser ceci
            [code]
            while read line
            do
            if test line = "*{" then
            aenlever='O' else
            if line = "*}" then
            aenlever='N'
            fi
            case $line in
            "\*{") # marche pas bien vu que caratère spécial unix astérisque et accolade!
            aenlever='O'
            aconserver = 'N'
            ;;
            "\*}")
            aenlever='N'
            ;;
            "\*")
            if test aenlever='O'then
            aconserver = 'N'
            else
            aconserver = 'O'
            fi
            ;;
            )
            aconserver = 'O'
            ;;
            esac
            if aenlever = 'N' and aconserver = 'O' then
            echo $line > fichier-out.txt
            fi
            done <fichier.txt
            [/code]
            C'est pas gagné.
            Encore merci
            c
            • [^] # Re: Heu précise exactement ce que tu veux...

              Posté par  . Évalué à 1.

              Bonsoir,

              Si je comprends bien : tu veux suprimer tout ce qu'il y a entre *{ et *} SAUF les lignes ne commençant pas par un * (ou TOUTES les lignes commençant par un *, y compris celles avec { et }). Ai-je bien compris ?

              Si c'est ça, il suffit de légèrement modifier l'expression régulière proposée. Cela donne :
              sed '/\*{/,/\*}/ s/\*.*//g' nom_fichier | grep -v '^$' >nouveau_fichier
              Cela ne supprimera que les lignes commençant par un * entre *{ et *}.

              J'espère avoir compris comme il faut. En tout cas avec tes fichiers de test ça marche, à condition que tu te sois trompré dans la 3ème ligne : {* au lieu de *{.

              Courage.
              • [^] # Re: Heu précise exactement ce que tu veux...

                Posté par  . Évalué à 1.

                Bonjour,

                La nuit portant conseil, je me suis aperçu que j'avais oublié le ^ qui permet de ne supprimer que les lignes commençant par * et non toutes les lignes contenant *. Désolé.

                Voici la correction :
                sed '/\*{/,/\*}/ s/^\*.*//g' nom_fichier | grep -v '^$' >nouveau_fichier

                J'espère que ça t'ira.
                • [^] # Re: Heu précise exactement ce que tu veux...

                  Posté par  . Évalué à 1.

                  Bonjour,

                  merci pour ta réponse elle correspond à ce que je recherchais.
                  Celle qui fonctionne c'est la première
                  sed '/\*{/,/\*}/ s/\*.*//g' nom_fichier | grep -v '^$' >nouveau_fichier
                  J'ai essayé bien des trucs et rien ne marchais par exemple des script sed vu qu'il fallait un condtionnement.
                  script.sed
                  /\*{/ {
                  :loop
                  /}\*/ {b end}
                  N
                  b loop
                  :end
                  s/\(\*{.*\)\*\(.*}\*\)/\1\2/
                  /^[:blank:]*$/d
                  }

                  puis sed -f script.sed < old > nouveau
                  Un temps fou pour rien et j'ai au moins appris des trucs sur sed :-)

                  Encore merci une solution "simple" et efficace.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.