Forum Programmation.shell Découpe de lignes de fichier texte

Posté par  .
Étiquettes : aucune
0
21
mar.
2006
Bonjour,

Dur dur le shell...

J'ai une petite question. Dans un fichier texte, pour chaque ligne, j'aimerais renvoyer sur la sortie standard, la partie de la ligne qui est à gauche ou à droite d'un caractère précis ou d'une chaîne de caractères.

Par exemple dans la ligne

955: NIVEAU MER 0 ECHEANCE 6.0 DATE 20060312000000

j'aimerais pouvoir récupérer ce qui est à gauche des ":" donc 955

ce qui est entre NIVEAU et ECHEANCE, donc MER 0

ce qui est entre ECHEANCE et DATE, donc 6.0
et ce qui est à droite de DATE donc 20060312000000

pour chaque ligne du fichier.

Quelle est la commande adéquate ? sed, grep, cat dans une boucle ?
Est-ce que le shell est la meilleure solution pour le traitement et le découpage galère de fichiers txt.

Merci à vous

Bib
  • # peut-etre bien que oui, peut-etre bien que non

    Posté par  . Évalué à 2.

    le shell est quasiement universel, donc tu pourras toujours faire tourner ta moulinette.

    pas forcement le plus adapté mais là encore ca depend aussi de la complexité du traitement, et de la taille des elements (un fichier txt de 10Ko c'est pas pareil qu'un de 10Mo).

    perl pourrait le faire, surement python ou autre.

    en shell :
    j'aurais bien pensé à grep suivi de colrm, mais les valeurs risquant de bouger (6.0 ne prend pas la meme place que 10.0) le colrm ne serait pas top.

    par contre il me semble que le cut pourrait t'aider.

    enfin si tu ne recherche qu'une valeur le grep valeur | cut ... pourrait suffir

    s'il te faut par contre parcourir tout le fichier, ligne par ligne pour traiter l'integralité du contenu, ca va etre long et lourd.

    mes 2cts sur la question.
    • [^] # sed

      Posté par  . Évalué à 2.

      J'avais aussi d'abord pensé à cut mais le fait que les délimiteurs ne soit pas toujours les mêmes (`:' ou espaces), ça complique un peu. Sinon, on peut d'abord donner un petit coup de sed pour déblayer tous les champs inutiles :

      $ sed -e "s/\([0-9]*\).*: NIVEAU \(.*\) ECHEANCE \(.*\) DATE \(.*\)/\1 \2 \3 \4/g" fichier.txt

      Ce qui devrait donner (sur ton exemple) :

      955 MER 0 6.0 20060312000000


      Après, tout dépend ce que tu veux faire de ces valeurs. Tu pourras envoyer ça dans un pipe vers awk par exemple pour un traitement de chaque champs...
      • [^] # Re: sed

        Posté par  . Évalué à 2.

        Je me relis et me rend compte que j'aurais pu expliciter un peu ce que fais sed dans cette commande (qui en passant devrait plutôt être sed -e "s/\([0-9]*\): NIVEAU \(.*\) ECHEANCE \(.*\) DATE \(.*\)/\1 \2 \3 \4/g" fichier.txt:

        o s/motif1/motif2/g indique de remplacer le motif1 par le motif2.
        o les parenthèses (protégées par un `\') servent à mémoriser des morceaux trouvés du motif1 pour les réutiliser dans le motif2. Dans motif2, on pourra utiliser \1 qui sera alors remplacé par le premier morceau mémorisé, \2 par le second, etc.
        o Le motif 1 est en fait une expression régulière qui correspond dans ce cas à la ligne à traiter :
           - \([0-9]*\): signifie un nombre quelconque (*) de caractères compris entre 0 et 9, et suivis de `:' (au passage, on mémorise ce nombre sans les `:'.
           - NIVEAU \(.*\) ECHEANCE signifie qu'ensuite on a n'importe quel nombre de n'importe quel caractère (.*) entourés par NIVEAU et ECHEANCE. De nouveau les parenthèses mémorise ce qu'on a trouvé entre NIVEAU et ECHEANCE.
           - pareil pour la suite...
        o Finalement on remplace toute la ligne par les morceaux mémorisés uniquement, séparés par des espaces (\1 \2 \3 \4).

        Voilà. L'explication est un peu laborieuse mais en creusant un peu ça devrait être décryptable.
  • # awk

    Posté par  . Évalué à 2.

    Si ton fichier est toujours dans le meme format :

    awk -F : '{print $1}' nomdufichier

    Pour la deuxieme question, awk est extremement performant pour le traitement des fichiers texte.
    • [^] # Re: awk

      Posté par  . Évalué à 2.

      Bon désolé j'ai pas lu la question en entier. La bonne réponse etant :

      sed 's/://g' nomdufichier | awk '{print $1 " " $3 " " $4 " " $6 " " $8}'
      • [^] # Re: awk

        Posté par  . Évalué à 3.

        pourquoi sed et awk alors que awk est capable de le faire seul comme un grand:

        echo "955: NIVEAU MER 0 ECHEANCE 6.0 DATE 20060312000000" | awk '{ split($1,toto,/:/)
        print toto[1] " " $3 " " $4 " " $6 " "$8 } '


        ou alors:

        echo "955: NIVEAU MER 0 ECHEANCE 6.0 DATE 20060312000000
        " | awk '{ sub (/:/,"",$1)
        print $1 " " $3 " " $4 " " $6 " "$8 } '
        955 MER 0 6.0 20060312000000

        Plus élégant:

        echo "955: NIVEAU MER 0 ECHEANCE 6.0 DATE 20060312000000
        " | awk '{ sub (/:/,"",$1)
        printf("%s %s %s %s %s\n",$1,$3,$4,$6,$8) } '
        955 MER 0 6.0 20060312000000
        • [^] # Re: awk

          Posté par  . Évalué à 2.

          S'il te plait évite un cat fichier | awk '{ (....)}'
          Fais plutot un awk '{ (...............;) }' fichier.
          Merci.
  • # Merci à tous

    Posté par  . Évalué à 1.

    En fait j'ai compilé un peu toutes vos réponses. J'ai utilisé sed pour remplacer les espaces par ":" et puis awk ensuite pour récupérer les champs qui m'intéressent.

    Merci encore à vous pour votre précieuse aide.

    Bib

Suivre le flux des commentaires

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