IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Shell et commandes GNU Discussion :

Un problème de traitement de fichiers ASCII


Sujet :

Shell et commandes GNU

  1. #1
    Membre averti
    Inscrit en
    Avril 2009
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : Avril 2009
    Messages : 47
    Par défaut Un problème de traitement de fichiers ASCII
    Bonjour à tous,

    Mes compétences en termes de programmation sont très limitées mais je fais actuellement face à une tâche qui rend l'écriture d'un code indispensable.

    J'ai une série de fichiers ASCII de 4 colonnes. Ces fichiers sont absolument énormes (de l'ordre de la centaine de millions de lignes chacun). Il s'agit de fichiers de topographie de haute résolution. Les colonnes sont les suivantes: (1) Longitude (2) Latitude (3) Une série de nombres qui ne me servent à rien et que je veux supprimer et (4) Altitude.

    Toutefois, à intervalles aléatoires, il arrive que dans la colonne (1), au lieu de la longitude, apparaisse le mot "Line" (je vous passe les détails mais c'est lié à la manière dont les données ont été acquises). Du coup chacune des lignes où il est écrit "Line" est en fait une scorie que je veux supprimer.

    Donc, pour résumer, je voudrais un code qui me vire la colonne n°3 et qui, à chaque fois qu'il y a écrit le mot "Line" (au lieu d'une valeur de longitude) dans la colonne (1), me vire aussi la ligne correspondante.

    Je vous avoue que vous me sauveriez la vie (et des semaines d'un travail excessivement casse-pied), si vous pouviez me faire part de votre expertise pour me sortir de ce mauvais pas...

    Je vous remercie par avance!

  2. #2
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    Je sais que la combinaison des commandes "sed" et "awk" sous Linux fait des miracles.
    Je ne sais pas si vous êtes sous Linux ou pas.

  3. #3
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    Cela vaut ce que cela vaut mais voici un exemple pour la suppression de la colonne 3...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    sirius:/utilitaires/shell/forum # more ascii.txt
    colonne1        colonne2        colonne3        colonne4
    1       2       3       4
    5       6       7       8
    9       10      11      12
    13      14      15      16
    sirius:/utilitaires/shell/forum # awk '{$3="";print $0}' ascii.txt
    colonne1 colonne2  colonne4
    1 2  4
    5 6  8
    9 10  12
    13 14  16
    Les tabulations sont utilisées pour délimiter les colonnes...
    Ensuite je suis en train de vérifier comment virer les lignes contenant "Line"... ça fait un bail que j'ai plus utilisé ni 'awk' ni 'sed' ^^

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Bonjour,

    Citation Envoyé par hurukan Voir le message
    Ensuite je suis en train de vérifier comment virer les lignes contenant "Line"... ça fait un bail que j'ai plus utilisé ni 'awk' ni 'sed' ^^
    Puisqu'il s'agit de virer la ligne entière si c'est le cas, pourquoi pas avec grep -v, tout simplement ? Ensuite, awk est effectivement censé être approprié ici, mais $3="" vide la colonne sans la supprimer et remplace les séparateurs par des espaces en sortie :

    Donc, du coup :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    grep -v Line ascii.txt | sed -e 's/^\([^\t]*\t[^\t]*\t\)[^\t]*\t\(.*\)/\1\2/g'

    … devrait fonctionner (s'il s'agit bien de tabulations) mais si ça a l'air un peu abscons en l'état.

  5. #5
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    sed '/LINE/d' ascii2.txt && awk '{$3="";print $0}' ascii.txt > ascii2.txt

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    sirius:/utilitaires/shell/forum # more ascii.txt 
    colonne1        colonne2        colonne3        colonne4
    1       2       3       4
    5       6       7       8
    9       10      11      12
    13      14      15      16
    LINE    18      19      20
    21      22      23      24
    25      26      27      28
    29      30      31      32
    LINE    34      35      36
    37      38      39      40
    LINE    42      43      44
    45      46      47      48
     
    sirius:/utilitaires/shell/forum # sed '/LINE/d' ascii2.txt && awk '{$3="";print $0}' ascii.txt > ascii2.txt
    colonne1 colonne2  colonne4
    1 2  4
    5 6  8
    9 10  12
    13 14  16
    21 22  24
    25 26  28
    29 30  32
    37 38  40
    45 46  48
     
    sirius:/utilitaires/shell/forum #
    sed '/LINE/d' ascii2.txt && awk '{$3="";print $0}' ascii.txt > ascii2.txt
    Fonctionnerait si nous nous trouvions sous Linux, j'ignore si awk et sed sont disponibles dans l'environnement Windows.

    Non en fait ça ne marche pas, en effet awk va virer les tabulations :{
    Et si ascii2.txt n'existe pas il ne se créera pas avec le '&&'...

    awk '{$3="";print $0}' ascii.txt > ascii2.txt && sed '/Line/d' ascii2.txt donne de meilleurs résultats si ascii2.txt n'existe pas.

    Cependant je n'ai plus les tabulations comme séparateur...

    [EDIT]
    awk -v OFS="\t" '{$3="";print $0}' ascii.txt > ascii2.txt && sed '/Line/d' ascii2.txt à l'air de proposer quelque chose de correct.

  6. #6
    Membre émérite
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Par défaut
    Hello,
    ah ben oui … c'est bien plus simple de prétraiter le fichier. Sous *nix il y a aussi cut. Il faut juste faire attention au délimiteur de colonne. Avec \t on pourrait imaginer un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    grep -v Line le_gros_fichier | cut -d\t -f 1,2,4 > gros_fichier_traité
    ici le grep filtre les lignes qui ne contiennent pas Line, cut les récupère et n'affiche que les colonnes 1,2 et 4.

    Ou avec un awk :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    awk -F \t '!/Line/ {print $1,$2,$4;}' le_gros_fichier > gros_fichier_traité
    -F est un option qui spécifie la valeur de la variable FS qui contient les séparateurs de champs, /.../ permet de spécifier une regex qui filtre les lignes, le ! étant la négation ⇒ !/Line/ ne retenant que les lignes ne contenant pas le mot Line.

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Hello

    Citation Envoyé par WhiteCrow Voir le message
    ah ben oui … c'est bien plus simple de prétraiter le fichier. Sous *nix il y a aussi cut. Il faut juste faire attention au délimiteur de colonne. Avec \t on pourrait imaginer un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    grep -v Line le_gros_fichier | cut -d\t -f 1,2,4 > gros_fichier_traité
    Ah bon sang ! J'avais pas pensé à cut, alors que je l'utilise presque tous les jours :-) Bien vu !

    Je ne suis pas sûr que la ligne de commande acceptera -d\t en l'état mais par contre, la tabulation est le délimiteur par défaut choisi par cut. Donc le plus concis qu'on puisse faire à mon avis est :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    grep -v Line ascii.txt | cut -f1,2,4-

    (Le tiret final après le chiffre signifiant « 4 et suivants »).

  8. #8
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    Obsidian vainqueur ^^

    C'étaient donc grep et cut qui faisaient des miracles ^^

  9. #9
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Citation Envoyé par hurukan Voir le message
    Obsidian vainqueur ^^
    Ah non non, c'est vous qui avez tout creusé ! Moi j'ai juste fait la synthèse :-)

  10. #10
    Membre émérite
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Juillet 2020
    Messages
    352
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Juillet 2020
    Messages : 352
    Par défaut
    Ndm : message restauré car le fil a initialement été posté dans le forum « langage C »

    Bah le one-liner en awk n'est pas mal non plus … en plus c'est plus facilement extensible.
    Sinon avec tcc on peut faire un quick & dirty :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    #! /usr/bin/env -S tcc -run
     
    #include <stdio.h>
    #include <string.h>
     
    int main(void)
    {
    	char cols[4][1000];
    	int res;
    	while ( (res=scanf("%s %s %s %s", cols[0], cols[1], cols[2], cols[3]))==4) {
    		if (strcmp(cols[0],"LINE")) {
    			printf("%s\t%s\t%s\n", cols[0], cols[1], cols[3]);
    		}
    	}
    }

  11. #11
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    Oui... avec un fscanf() alors... pour lire jusqu'à ce qu'il n'y ait plus rien à lire...

  12. #12
    Membre émérite Avatar de balkany
    Homme Profil pro
    Touriste
    Inscrit en
    Juillet 2017
    Messages
    348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Touriste

    Informations forums :
    Inscription : Juillet 2017
    Messages : 348
    Par défaut
    Ça aurait été bien que Flo Flo précise quel est le séparateur de champs du fichier en question, mais en supposant comme les précédents intervenants que c'est une tabulation, je pense que le mieux serait de faire ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk 'BEGIN{OFS=FS="\t"} ($1 !~ "Line"){print($1,$2,$4)}' fichier_entrée > fichier_sortie
    Contrairement à ce qui a été proposé plus haut (je crois) on n'exclut une ligne que si le premier champ contient "Line", ce qui ne devrait rien changer au résultat puisque les autres champs ne sont censés contenir que des nombres, mais bon, autant limiter la recherche au champ concerné.
    De plus, le séparateur de champs est préservé en sortie.

  13. #13
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 358
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 358
    Par défaut
    Pour sed, une méthode moins compliquée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    sed '/^Line/d;s/\t[^\t]*//2' fichier
    Et la version built-in:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    while read a b c d; do [[ /Line/ =~ $a ]] || printf "%s\t%s\t%s\n" "$a" "$b" "$d" ; done <fichier

  14. #14
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 664
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  15. #15
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 358
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 358
    Par défaut
    qu'est-ce qui choque ?

  16. #16
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Pour sed, une méthode moins compliquée:
    Et la version built-in:
    Joli !

  17. #17
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 664
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    qu'est-ce qui choque ?
    les barres obliques,
    mais surtout, que le motif recherché (la regex) n'est pas à droite.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  18. #18
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 358
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 358
    Par défaut
    c'est vrai, la syntaxe devrait être [[ $a =~ Line ]] , d'ailleurs, pourquoi une regex un simple [[ $a = Line ]] est suffisant d'après le besoin...

    L'autre fonctionne par chance car $a est valide en tant que regex pour /Line/ puisque celle-ci prendra Line en tant que regex...

  19. #19
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 664
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 664
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    d'ailleurs, pourquoi une regex un simple [[ $a = Line ]] est suffisant d'après le besoin...
    et pourquoi des crochets doubles ?
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  20. #20
    Expert confirmé Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 358
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 358
    Par défaut
    ça prend moins de caractères puisque l'on ne met pas les guillemets...

    Et une autre version awk (pour le fun) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk 'BEGIN{FS="\t";OFS=FS}{$3=$4;NF+=-1}$1!~"Line"' fichier

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Probléme de traitement de fichiers
    Par magni2009 dans le forum Débuter
    Réponses: 1
    Dernier message: 18/05/2010, 20h20
  2. Problème de traitement de fichier ini
    Par pilipi dans le forum WebDev
    Réponses: 3
    Dernier message: 16/01/2009, 04h20
  3. Réponses: 3
    Dernier message: 25/06/2008, 10h39
  4. Réponses: 13
    Dernier message: 24/10/2006, 14h17
  5. Réponses: 5
    Dernier message: 03/08/2006, 20h40

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo