Forum Programmation.shell Remplacer une valeur dans une colonne sous condition

Posté par (page perso) . Licence CC by-sa.
Tags :
1
5
juin
2018

Bonjour à tous,

J'ai une liste de fichiers textes contenant des valeurs séparées par des ; . Dans ces fichiers je dois remplacer la valeur de colonne 8 pour les lignes commençant par la valeur PAR.

Pour le moment j'utilise cette commande

for i in `ls *.txt`; do cat $i | awk -i inplace -F";" '{ if($1=="PAR") {gsub("[^0-9]","3027008440109",$8);print} }'; done
Malheureusement sa marche pas vraiment, j'ai cette erreur

awk: inplace:47: avertissement : inplace_begin : modification sur place annulée pour le fichier incorrect « - »
Je comprends pas vraiment l'erreur

Exemple de fichier :

@GP;WEB@EDI;INVOIC;STANDARD;;;;
ENT;06183032;23/05/2018;;;;29/05/2018;xxxxxxxxx;;;;;qqqqqqqqqq;31/05/2018 00:00;15/07/2018;FACTURE;EUR;08/06/2018;0;qqqqqqqqqq;;0;8;0;0;0;60;MAR;0;;
DTM;263D;31/05/2018
PAR;3027008446064;blablabla;3014597000104;blobloblo;3027008446064;bliblibli;3027008446064;blublublu;;;3014597000104;blablabla;;;
LIG;1;3253560867751;REFE;1;0;PCE;2;19.92;EUR;;;20;38.84;0;DESI;39.84;;0;0;0;;;;;0;0;;;;0;0;;;0;;;;;;0;
[...]

  • # UUOC and UUOls

    Posté par . Évalué à 5 (+3/-0).

    for i in *.txt remplacera avantageusement le for i in ls *.txt, de meme que awk ' ….' $i remplacera cat $i | awk …

    • [^] # Re: UUOC and UUOls

      Posté par . Évalué à 2 (+1/-1).

      Pour être plus précis: si j'ai bien compris, l'option inplace permet de modifier directement le fichier par awk (un peu comme l'option -i de sed). Mais à cause de l'UUOC, awk ne connait pas le fichier que tu veux modifier : il prend ses données depuis stdin.

      Encore une raison de se débarasser de ces sales UUOC.

    • [^] # Re: UUOC and UUOls

      Posté par (page perso) . Évalué à 2 (+1/-0).

      C'est plus propre comme tu le propose, j'arrive à ce résultat sauf que ça me vide les fichiers

      for i in *.txt; do awk -i inplace -F";" '{ if($1=="PAR") {gsub("[^0-9]", "3027008440109", $8);} }' $i; done

      Born to Kill EndUser !

      • [^] # Re: UUOC and UUOls

        Posté par . Évalué à 3 (+1/-0). Dernière modification le 05/06/18 à 18:36.

        tu as supprimé le print, pourquoi ? C'est normal dans ce cas que tes fichiers soient vides :)

        • [^] # Re: UUOC and UUOls

          Posté par (page perso) . Évalué à 2 (+1/-0).

          il m'affichait le résultat sans faire la modification.

          Born to Kill EndUser !

          • [^] # Re: UUOC and UUOls

            Posté par . Évalué à 3 (+1/-0). Dernière modification le 05/06/18 à 18:46.

            Je suppose une erreur dans le gsub : que veux-tu faire exactement ?

            chez moi :

            $ echo "a b 1234" | awk '{gsub("[^0-9]","42",$3) ; print }'
            a b 1234
            

            Par contre un truc du genre :

            $ echo "a b 1234" | awk '{gsub("^[0-9]*","42",$3) ; print }'
            a b 42
            

            ferait mieux l'affaire

            • [^] # Re: UUOC and UUOls

              Posté par . Évalué à 3 (+1/-0). Dernière modification le 05/06/18 à 18:51.

              Mieux, si tu dois remplacer systématiquement la colonne , tu fais un truc du genre:

              echo "a b 1234" | awk '{$3 = 42 ; print }'
              a b 42
              

              Dans mon exemple je remplace systématiquement la colonne 3. Dans ton cas, remplace le gsub par $8 = valeur_que_tu_veux_forcer dans ton expression.

            • [^] # Re: UUOC and UUOls

              Posté par (page perso) . Évalué à 2 (+1/-0). Dernière modification le 06/06/18 à 08:50.

              Je pense que mon premier message n'était pas clair, du coups j'ai modifié mon message initial avec un exemple de fichier.

              Avec cette commande :

              for i in *.txt; do awk -i inplace -F";" '{ if($1=="PAR") {gsub(/[0-9]/, "3027008440109", $8);print} }' $i; done

              Il me fait bien le remplacement mais il m'efface tout le contenue du fichier et garde que la ligne identifié par awk.

              Born to Kill EndUser !

              • [^] # Re: UUOC and UUOls

                Posté par . Évalué à 3 (+1/-0).

                Normal, puisque tu ne fais le print que s'il y a remplacement. Il faut que tu sortes le print du bloc qui est exécuté lorsque tu rencontres la chaine 'PAR'.

                Ensuite, ta regexp dans le gsub me pose un petit problème: dans ton cas, tu lui demandes de remplacer tous les chiffres de ta colonne par "3027008440109". Si tu as 3 chiffres, il va te reproduire 3 fois la chaine ""3027008440109"". Est-ce bien ce que tu veux ?

                exemple :

                 echo ' a b c 1234' | awk '{ gsub (/[0-9]/,"azert", $4);print }'
                
                
                • [^] # Re: UUOC and UUOls

                  Posté par (page perso) . Évalué à 1 (+0/-0).

                  Normal, puisque tu ne fais le print que s'il y a remplacement. Il faut que tu sortes le print du bloc qui est exécuté lorsque tu rencontres la chaine 'PAR'.

                  ah

                  Ensuite, ta regexp dans le gsub me pose un petit problème: dans ton cas, tu lui demandes de remplacer tous les chiffres de ta colonne par "3027008440109". Si tu as 3 chiffres, il va te reproduire 3 fois la chaine ""3027008440109"". Est-ce bien ce que tu veux ?

                  Exemple de fichier original

                  @GP;WEB@EDI;INVOIC;STANDARD;;;;
                  ENT;06183032;23/05/2018;;;;29/05/2018;xxxxxxxxx;;;;;qqqqqqqqqq;31/05/2018 00:00;15/07/2018;FACTURE;EUR;08/06/2018;0;qqqqqqqqqq;;0;8;0;0;0;60;MAR;0;;
                  DTM;263D;31/05/2018
                  PAR;3027008446064;blablabla;3014597000104;blobloblo;3027008446064;bliblibli;3027008446064;blublublu;;;3014597000104;blablabla;;;
                  LIG;1;3253560867751;REFE;1;0;PCE;2;19.92;EUR;;;20;38.84;0;DESI;39.84;;0;0;0;;;;;0;0;;;;0;0;;;0;;;;;;0;

                  Résultat que je veux obtenir

                  @GP;WEB@EDI;INVOIC;STANDARD;;;;
                  ENT;06183032;23/05/2018;;;;29/05/2018;xxxxxxxxx;;;;;qqqqqqqqqq;31/05/2018 00:00;15/07/2018;FACTURE;EUR;08/06/2018;0;qqqqqqqqqq;;0;8;0;0;0;60;MAR;0;;
                  DTM;263D;31/05/2018
                  PAR;3027008446064;blablabla;3014597000104;blobloblo;3027008446064;bliblibli;3027008440109;blublublu;;;3014597000104;blablabla;;;
                  LIG;1;3253560867751;REFE;1;0;PCE;2;19.92;EUR;;;20;38.84;0;DESI;39.84;;0;0;0;;;;;0;0;;;;0;0;;;0;;;;;;0;

                  Le changement est sur la ligne commençant par PAR colonne 8.

                  Born to Kill EndUser !

                  • [^] # Re: UUOC and UUOls

                    Posté par (page perso) . Évalué à 1 (+0/-0).

                    J'avance sur mon problème et il me reste juste à trouver comment lui dire de remplacer tout le contenue de la colonne 8 par une valeur et ce peu importe que se soit des chiffres, des lettres ou des bananes.

                    for i in *.txt; do awk -i inplace -F";" '{ if($1=="PAR") {gsub(/*/, "3027008440109", $8);} print }' $i; done
                    

                    Born to Kill EndUser !

                    • [^] # Re: UUOC and UUOls

                      Posté par (page perso) . Évalué à 1 (+0/-0). Dernière modification le 06/06/18 à 15:32.

                      ayeeeeee j'ai finiiiiiiiii

                      Je me suis rappelé du commentaire de M.Poil http://linuxfr.org/nodes/114651/comments/1740950 et le résultat est

                      for i in *.txt; do awk -i inplace -F";" 'BEGIN{OFS = FS}; { if($1=="PAR") {$8="3027008440109";} print }' $i; done
                      Merci à tous pour votre aide ;)

                      Born to Kill EndUser !

                      • [^] # Re: UUOC and UUOls

                        Posté par . Évalué à 3 (+1/-0).

                        for i in *.txt; do awk -i inplace -F";" 'BEGIN{OFS = FS}; { if($1=="PAR") {$8="3027008440109";} print }' $i; done

                        continuons à simplifier
                        ta boucle for n'apporte rien, ceci devrait faire le meme travail

                        awk -i inplace -F";" 'BEGIN{OFS = FS}; { if($1=="PAR") {$8="3027008440109";} print }' *.txt

  • # Quelques propositions

    Posté par (page perso) . Évalué à 3 (+2/-1).

    Le message d'erreur vient du fait que tu appelles awk pour traiter son entrée standard (qui est un flux et pas un fichier) et cela n'a pas de sens de le traiter “en place.”

    À part ça, quelques remarques en vrac:

    • Il vaut mieux utiliser (…)` que les backquotes, comme(ls *,txt)`.
    • Dans ce cas particulier, le shell le fait déjà, donc un simple for i in *.txt fait très bien l'affaire.
    • La plupart du temps cat $i ne sert à rien, il suffit de rediriger l'entrée standard: awk … < $i.
    • Dans ce cas particulier, tu peux directement soumettre ton fichier à awk, donc cat $i | awk … devient awk … $i et ton option inplace a du sens puisque sous cette forme tu traites un fichier!
    • [^] # Re: Quelques propositions

      Posté par (page perso) . Évalué à 3 (+2/-0).

      Si tu dois remplacer la valeur de la colonne 8 par une valeur fixe pas besoin de faire un gsub, $8="PAR3027008440109" et voilà
      Et pas besoin du for i in *; awk prend les glob.

      awk -i inplace -F";" '{ if ($4 ~ /^par/) { $4 = "par2018" }; print }' *.txt

      Mes fichiers en entrée

      aze;aze;aze;par12;aze;aze;aze
      aze;aze;aze;par13;aze;aze;aze
      aze;aze;aze;aze124;aze;aze;aze
      aze;aze;aze;par123;aze;aze;aze
      

      Mes fichiers en sortie

      aze aze aze par2018 aze aze aze
      aze aze aze par2018 aze aze aze
      aze;aze;aze;aze124;aze;aze;aze
      aze aze aze par2018 aze aze aze
      

      Is it a Bird? Is it a Plane?? No, it's Super Poil !!!

      • [^] # Re: Quelques propositions

        Posté par (page perso) . Évalué à 2 (+1/-0).

        Je me rend compte que le FS saute sur un print et un print $0 faut ajouter BEGIN {OFS = FS}

        Is it a Bird? Is it a Plane?? No, it's Super Poil !!!

      • [^] # Re: Quelques propositions

        Posté par (page perso) . Évalué à 3 (+1/-0).

        Et pas besoin du for i in *; awk prend les glob.

        En fait le shell :). J'ai effectivement oublié d'ajouter ça dans ma liste, un train à prendre sans doute. :)

Envoyer un commentaire

Suivre le flux des commentaires

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