Forum Programmation.shell Passer d'une liste monocolonne délimité à une liste sur plusieurs ligne.

Posté par  . Licence CC By‑SA.
Étiquettes : aucune
0
28
déc.
2016

Salut,
J'ai un fichier du type, qui fait 10k lignes:
[toto]
a
b
v
d
e
[/toto]
[toto]
zahoz
eoh
[/toto]

Et je souhaite le passer sous ce format.
[toto]abvde[/toto]
[toto]zahozech[/toto]

Je sais pas quel outils utiliser pour le faire? Vous me conseillez quoi?
J'ai pensé à awk, mais je ne sais pas comment l'utiliser :/
Merci :)

  • # Avec du shell simplement

    Posté par  (site web personnel) . Évalué à 1. Dernière modification le 28 décembre 2016 à 14:33.

    Vite fait, si t'es pas pressé pour l'exécution…

    while read a; do b='-n'; [[ "${a}" = '[/toto]' ]] && b=''; echo ${b} "${a}"; done

    Sinon pour awk y a le man

  • # toujours avec du shell et avec larache

    Posté par  . Évalué à 3.

    tout remettre sur une ligne, (avec sed par exemple qui va rechercher remplacer les sauts de ligne par 'rien'
    
    puis recouper apres chaque [/toto] (avec sed en remplacant les [/toto][toto] par [/toto]\n[/toto])
  • # Python

    Posté par  . Évalué à 2. Dernière modification le 28 décembre 2016 à 16:18.

    Un truc comme ça :

    with open("chemin_du_fichier", "rt") as f:
        toto = False
        for ligne in f.readlines():
            ligne = ligne[:-1] # enlève le saut de ligne
            if ligne == "[toto]":
                toto = True
                print("[toto]", end='')
            elif ligne = "[/toto]":
                toto = False
                print("[/toto]")
            elif toto:
                print(ligne, end='')

    Edit : ah, je viens de voir le nom du forum. C'est pas du Bash donc je suis peut-être hors sujet. Mais j'imagine que ça a l'avantage d'être rapide.

    • [^] # Re: Python

      Posté par  . Évalué à 4. Dernière modification le 29 décembre 2016 à 09:41.

      bof il parle de awk donc tu n'es pas hors sujet, peut être qu'il préfère juste de la ligne de commande :) genre

      perl -pe 's/(\[\/.*?]\n)|((.*)\n)/\1\3/g'

      ps : j'adore ce genre de connerie y a plus de caractères spéciaux que de lettres :P,

      bon sinon pour ceux qui aiment du code plus lisible

      #!/bin/env perl
      
      use strict;
      use warning;
      
      while(<>) # equivalent a while(<STDIN>)
      {
        if ( ! /^\[\// ) {  # si on ne commence pas par [/ (on peut aller plus loin et vérifier que c'est bien formé mais c'est pas le sujet
          chomp ; # on vire le dernier caractère si c'est un retour a la ligne 
        }
        print ; 
      }

      bien évidemment on peut aussi faire le précédent en onliner

      perl -pe 'if( ! /^\[\// ) { chomp ;}'

      et ça c'est cool et plus lisible que la version du haut :)
      bien évidemment avec l'option -i on peut remplacer le STDIN par des fichier comme avec sed :)

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: Python

        Posté par  . Évalué à 3.

        Je préfère : perl -pe 'chomp if not (/^\[\//)'

        • [^] # Re: Python

          Posté par  . Évalué à 2.

          certes, c'est aussi ma préférée (pas d'accolades), mais j'ai tendance à éviter lorsque je publie du code sur un forum d'aide, les gens n'ont pas l'habitude des conditions post-fixées;

          Après les gens pestent que perl est un WOL (write only language), en sortant des exemple de code abscons (un peu comme mon premier one liner).

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: Python

            Posté par  . Évalué à 2.

            Après les gens pestent que perl est un WOL (write only language), en sortant des exemple de code abscons (un peu comme mon premier one liner).

            Moi je viens des scripts shell à la base. Je m'étais mis à perl pour fuir awk :)

  • # Solution awk

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

    Ne pas prendre peur à cause des protections diverses et variées (crochets et slashes) :

    awk '/^\[toto\]$/,/^\[\/toto\]$/ {ORS=""; print $0} /^\[\/toto\]$/ {print "\n"}'

    À savoir tu veux recopier toute ligne entre [toto] et [/toto], en n'affichant pas de retour à la ligne entre chacune (d'où ORS à chaîne vide au lieu du retour à la ligne syndical), d'où la première partie ; et tu veux ajouter le retour à la ligne sur la balise fermante, d'où la seconde partie.

    Debian Consultant @ DEBAMAX

  • # Avec awk

    Posté par  . Évalué à 1.

    Avec un fichier toto et awk:

    awk '{ printf $0 } $0 ~ /[\/toto]/ { print "" }' toto

    Le premier bloc avec printf n'affiche pas le séparateur (RS est un retour à la ligne par défaut).

    Le deuxième bloc avec print, qui vérifie avant la chaîne "[/toto]", affiche juste le séparateur (un retour à la ligne).

    • [^] # Re: Avec awk

      Posté par  . Évalué à 1.

      dsl…:
      awk '{ printf $0 } $0 ~ /\[\/toto\]/ { print "" }' toto

      • [^] # Re: Avec awk

        Posté par  . Évalué à 1.

        Ca marche comme ça aussi :):

        awk '{ printf $0 } /\[\/toto\]/ { print "" }' toto

        • [^] # Re: Avec awk

          Posté par  . Évalué à 1.

          Mais c'est beaucoup plus lent que la réponse postée précédemment par Cyril.

Suivre le flux des commentaires

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