Forum Programmation.shell SED ^^

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
2
30
avr.
2018

A la recherche d'un grand gourou du SED …
j'ai un fichier de 100 de ligne sur une 10 de colonnes avec des références des désignations et des prix.
Csv séparer par des ; et "" pour les champs.
Je voudrais remplacer les . par des , dans la colonne des prix.= et seuelement dans la colonne des prix.

sed -i -e 's/./,/g' master.csv => ca me touche toute les colonnes :(

J'aimerai en gros faire une ligne avec des expressions régulière pour taper juste sur la colonne des prix.
en gros changer 55.55 en 55,55

sed -i -e "s/[0-9]/./[0-9][0-9]/???????????????/" master.csv

Merci d'avance

  • # probablement pas le bon outil

    Posté par  . Évalué à 3.

    Il y a moyen que awk soit plus adapté, mais si tu tiens à utiliser sed, alors il te faudra hard-coder la position de la colonne qui t'intéresse, par exemple si c'set en 3ème position (en partant de 1) et en supposant que ce caractère n'intervienne qu'une seule fois par champ: sed -i 's/^\([^;]*;[^;]*;[^.]\)\.\(.*)$/\1,\2/g'.

    Bon, on peut probablement mieux faire, même avec sed, mais bon, awk aurait été plus adapté à mon sens (même si je ne saurais pas le faire vite fait).

    À savoir que mon exemple échoue dès lors que tu te retrouves avec des champs contenant un ; échappé avant la colonne de prix, aussi.

  • # pour traiter des colonnes, awk est mieux adapté (et est plus lisible au passage)

    Posté par  . Évalué à 3.

    sinon, ce serait bien d'avoir un exemple de ton fichier.

    Mais en suposant que tu as un truc du genre en entrée :

    ref1; designation1,abc ;  42,32
    ref2; designation2,def ; 33,25
    

    et que tu veuilles remplacer la virgule par un point dans la 4eme colonne, essaier ça :

    $ echo "ref1; designation1,abc ;  42,32                                                                                                                                                       ref2; designation2,def ; 33,25" |awk '{sub(",",".",$4); print}'
    ref1; designation1,abc ; 42.32
    ref2; designation2,def ; 33.25
    
    • [^] # Re: pour traiter des colonnes, awk est mieux adapté (et est plus lisible au passage)

      Posté par  . Évalué à 1.

      "1";"1";"";"1416518";"910-000808";"LOGITECH";"5099206010109";"LOGITECH MARBLE MOUSE";"13";"40.15";"47.99";"Peripherique";"Peripherique entree";"Souris et Clavier";"";",285"

      Voila une des lignes de mon fichier
      en gros au 10 champs j'ai le prix avec des . que je veux transformer en ,
      Je connais pas du tout la commande AWK (qui à l'air puissante)
      Je travail toujours avec des sed -i pour modifier directement mon fichier
      Je vais avoir un truc comme ca ?

      awk '{sub(".",",",$10); print}' master.csv

      le print ne me modifie pas mon fichier ? il me l'affiche c'est tout ?

      merci d'avance totof2000

      • [^] # Re: pour traiter des colonnes, awk est mieux adapté (et est plus lisible au passage)

        Posté par  . Évalué à 4.

        Pour awk, sed, et autres outils unix, il y a un site que j'aime bien: grymoire. C'est pas joli, ça cause pas le https, mais c'est bien foutu et c'est efficace pour peu qu'on lise l'anglais.
        Ce que j'appelle bien foutu, c'est des exemples minimaux (donc, qui n'illustrent qu'un seul point) et des explications pour aller avec.

        M'enfin, en gros, awk travaille ligne par ligne, comme sed, mais en plus, il ajoute 2 notions importantes: les champs, et un langage de programmation. Les premiers te permettent de manipuler (les manipulations supportent les regex, au passage) une ligne par champs (mais il peut être nécessaire de spécifier le séparateur, comme dans ton cas) et le 2nd te permets entres autre de ne déclencher des traitement que quand une condition à été remplie, par exemple parser la 1ère ligne pour savoir quelle colonne contiens le champs que tu souhaites manipuler.

        Pour le reste, je te laisse à la doc, elle sera plus explicite que moi.

        • [^] # Re: pour traiter des colonnes, awk est mieux adapté (et est plus lisible au passage)

          Posté par  . Évalué à 1.

          J ai avancer sur le AWK

          echo '"1";"1";"";"1416518";"910-000808";"LOGITECH";"5099206010109";"LOGITECH MARBLE MOUSE";"13";"40.15";"47.99";"Peripherique";"Peripherique entree";"Souris et Clavier";"";",285"' | awk -F";" '{sub(".","1",$10); print}'

          "1" "1" "" "1416518" "910-000808" "LOGITECH" "5099206010109" "LOGITECH MARBLE MOUSE" "13" 140.15" "47.99" "Peripherique" "Peripherique entree" "Souris et Clavier" "" ",285"

          Pourquoi ma commande marche pas ? il faut de spécialisé le point ? car ce me modifie le premier caractere du champ et pas le . (point)

          • [^] # Re: pour traiter des colonnes, awk est mieux adapté (et est plus lisible au passage)

            Posté par  . Évalué à 2. Dernière modification le 02 mai 2018 à 16:38.

            Le premier paramètre de la fonction sub est une expression régulière. Donc le point est interprété comme étant un caractère quelconque. La substitution se fera donc sur le premier caractère de ton champ. Exemple :

            $ echo "ref1; designation1,abc ;  42,32
            ref2;designation2,def ; 33,25" \| awk '{sub(".","!",$4); print}'
            ref1; designation1,abc ; !2,32
            ref2; designation2,def ; !3,25

            Pour pouvoir utiliser le point, il faut le protéger avec un double backslash:

            $ echo "ref1; designation1,abc ;  42,32
            ref2; designation2,def ; 33,25" | awk '{sub("\\.","!",$4); print}'
            ref1; designation1,abc ;  42,32
            ref2; designation2,def ; 33,25

            Voici ce que retourne le man de awk sous freebsd :

                 sub(r, t, s)     Substitutes t for the first occurrence of the regular
                                  expression r in the string s.  If s is not given, $0 is
                                  used.  An ampersand (&) in t is replaced in string s
                                  with regular expression r.  A literal ampersand can be
                                  specified by preceding it with two backslashes (\\).
                                  A literal backslash can be specified by preceding it
                                  with another backslash (\\).  sub() returns the number
                                  of replacements.
  • # US -> Fr

    Posté par  . Évalué à 1.

    Si tu veux transformer toutes les notations décimales US en Fr : sed -i "s/\([0-9]*\)\.\([0-9]*\).*/\1,\2/g" data.txt

    Si tu veux modifier une colonne précise, précise là, il suffit d'indiquer le nombre de séparateurs.

    • [^] # Re: US -> Fr

      Posté par  . Évalué à 1.

      dac .. et du coup pour précise le nombre de séparateurs ?

      • [^] # Re: US -> Fr

        Posté par  . Évalué à 2.

        Exemple ici mais c'est hard-codé. Pas le choix, avec sed.

  • # une bonne référence pour sed

    Posté par  . Évalué à 2.

    • [^] # Re: une bonne référence pour sed

      Posté par  . Évalué à 2.

      Pfff… j'étais en train de le dire -.-' tu m'as devancé. Par contre y'a pas que sed.

      • [^] # Re: une bonne référence pour sed

        Posté par  . Évalué à 2.

        c'était déloyal, j'aurais du poster mon commentaire dans la section liens ;-)

        • [^] # Re: une bonne référence pour sed

          Posté par  . Évalué à 2. Dernière modification le 30 avril 2018 à 22:02.

          Nah, grymoire mériterais plus qu'un simple lien, à mon sens, mais il est si ancien (comme il se doit pour un tel ouvrage) que je doute qu'un bookmark serait accepté :) ou alors, il faudrait une collection de liens de ce niveau, par thèmes. Un truc pour aider les gens à la barbe naissante tout comme ceux pour qui elle est déjà fleurie.

          Pour la 1ère catégorie, je commence à penser qu'il faudrait un tutoriel sur l'utilisation de linuxfr…

  • # Perl6

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

    Perl6 a en natif les Grammar. Tu définies une grammaire et hop, c'est finit en quelques lignes !

    • [^] # Re: Perl6

      Posté par  . Évalué à 1.

      J ai avancer sur le AWK

      echo '"1";"1";"";"1416518";"910-000808";"LOGITECH";"5099206010109";"LOGITECH MARBLE MOUSE";"13";"40.15";"47.99";"Peripherique";"Peripherique entree";"Souris et Clavier";"";",285"' | awk -F";" '{sub(".","1",$10); print}'

      "1" "1" "" "1416518" "910-000808" "LOGITECH" "5099206010109" "LOGITECH MARBLE MOUSE" "13" 140.15" "47.99" "Peripherique" "Peripherique entree" "Souris et Clavier" "" ",285"

      Pourquoi ma commande marche pas ? il faut de spécialisé le point ? car ce me modifie le premier caractere du champ et pas le . (point)

  • # avec sed

    Posté par  . Évalué à 1. Dernière modification le 01 mai 2018 à 07:39.

    Bonjour

    Remplacer le point par une virgule dans chaque suite de caractères (entourée de guillemets)
    dont le contenu est composé d'une suite de chiffres séparée par un point d'une autre suite de 2 chiffres.

    michel@debg53sw:~$ echo '"LOGITECH";"40.15";"47.99";"13";",285"' | sed 's/\(\"[0-9]*\)\.\([0-9]\{2\}\"\)/\1,\2/g'
    "LOGITECH";"40,15";"47,99";"13";",285"
    michel@debg53sw:~$ 
    
    
    • [^] # Re: avec sed

      Posté par  . Évalué à 2. Dernière modification le 01 mai 2018 à 07:50.

      Mais ce n'était pas la peine d'échapper les caractères guillemets,
      donc, simplement avec :

       sed 's/\("[0-9]*\)\.\([0-9]\{2\}"\)/\1,\2/g'
      
  • # Vim

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

    Juste parce que je suis en train de lire "Practical vim" :p

        qa09f;wvi":s/\./,/<cr>q
        u
        :%normal @a
    

    Pour les explications:

    • on crée une macro enregistrée dans le registre a qui:
      • va en début de ligne (0)
      • cherche ensuite le 9ème point virgule sur la ligne, pour atteindre la 10ème colonne (9f;)
      • sélectionne visuellement le champ correspondant à cette dixième colonne (wvi")
      • remplace le point par une virgule dans la sélection (:s/\./,/\<cr\> — il faut appuyer sur entrée là où il y a écrit <cr>)
      • le dernier q indique que la macro est terminée
    • ensuite on annule la modification qu'on vient de faire (u)
    • on applique la macro du registre a (@a) à toutes (%) les lignes du fichier en mode normal (:normal)

    Profit !

  • # Non je ne suis pas un gourou

    Posté par  . Évalué à 1.

    Salut,

    Sans être un grand gourou de sed, et si et seulement si toutes les lignes de ton fichier sont du même acabit que l'exemple donné plus haut, alors ta 1ère syntaxe était presque la bonne. Fallait juste omettre le "g" (global) pour que la syntaxe ne s'applique qu'à la 1ère occurrence ;-)

    sed -i 's/./,/' master.csv

    ;-)

Suivre le flux des commentaires

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