[awk] découper un fichier en plusieurs fichiers

Résolu
DIE -  
 DIE -

Bonjour à tous et toutes

Je tourne en rond sur un script qui doit etre 100% en awk, mais je me demande si c'est possible finalement. J'ai essayé avec chatGPT mais il me sort n'importe quoi :-(

Voici mon problème :

  • Dans le fichier suivant, je veux créer un nouveau fichier à chaque fois que l'on rencontre le mot PAGE dans le fichier d'entrée. La ligne contenant ce mot PAGE est reportée au début du fichier nouvellement créé.
  • Si quelque part dans le fichier, après le mot PAGE, on trouve le mot NIR, alors la variable NIR est corrigée en conséquence et est utilisée pour nommer ce fichier. Le fichier est porte le comme nom la valeur de la variable NIR, suivie de l'extension ".txt".

Exemple :

  • Fichier d'entrée :
 totot
 titi PAGE
 tata
 tata
dfdf fdf NIR un deux troix quatre
tata
dfdfd
dfdfdf dfdf PAGE
dfd
fdfdfd
dfdf
dfddfdfdf NIR one two three four five
dfdf
df PAGE
dfdf NIR dfdf
dfdfd

Résultat attendu :

  • Le premier fichier créé s'appelle un.txt et contient :
 titi PAGE
 tata
 tata
dfdf fdf NIR un deux troix quatre
tata
dfdfd

Le deuxième fichier créé s'appelle one.txt et contient :

dfdfdf dfdf PAGE
dfd
fdfdfd
dfdf
dfddfdfdf NIR one two three four five
dfdf
  • Le troisième fichier créé s'appelle dfdf.txt et contient :
df PAGE
dfdf NIR dfdf
dfdfd

Merci d'avance
Windows / Firefox 122.0

4 réponses

  1. dubcek Messages postés 18627 Date d'inscription   Statut Contributeur Dernière intervention   5 660
     

    hello

    essayer

    $ awk 'BEGIN {while(getline < "fichier")if($0 ~ /NIR/)for(n=1; n<=NF; n++)if($n ~ /NIR/)t[++f]=$(n+1)} /PAGE/ {a=t[++x] ".txt"} a {print $0 > a }' fichier
    $
    $ more *txt
    ::::::::::::::
    dfdf.txt
    ::::::::::::::
    df PAGE
    dfdf NIR dfdf
    dfdfd
    ::::::::::::::
    one.txt
    ::::::::::::::
    dfdfdf dfdf PAGE
    dfd
    fdfdfd
    dfdf
    dfddfdfdf NIR one two three four five
    dfdf
    ::::::::::::::
    un.txt
    ::::::::::::::
    titi PAGE
    tata
    tata
    dfdf fdf NIR un deux troix quatre
    tata
    dfdfd
    
    1
  2. mamiemando Messages postés 33174 Date d'inscription   Statut Modérateur Dernière intervention   7 944
     

    Bonjour,

    J'ai réécris le message initial car certaines tournures étaient ambiguës et ça ne m'étonne pas que ChatGPT se soit pris les pieds dans le tapis (je ne pense pas d'ailleurs que ChatGPT soit capable de résoudre proprement un exercice de programmation non trivial, mais bref).

    Quoi qu'il en soit, la définition du problème est incomplète :

    • Que se passe-t-il (et doit-il se passer) si le mot clé NIR ne figure pas après le mot PAGE ?
      • Crées-tu quand même un nouveau fichier ?
      • Si oui, comment le nommes-tu ?

    Bonne chance

    0
    1. DIE
       

      bjr mamiemando,

      Il y aura forcément le mot NIR entre deux mot PAGE donc c ok pour moi :)

      0
  3. DIE
     

    ça marche SENSATIONNELLEMENT BIEN :)
    mille merci

    Je comprends pas comment marche le t[++f] par rapport au t[++x]  si tu peux m'éclairer

    0
    1. mamiemando Messages postés 33174 Date d'inscription   Statut Modérateur Dernière intervention   7 944
       

      Ce sont juste deux variables différentes, mais qui désignent dans les deux cas les index du tableau t.

      • Dans un premier temps, au lancement du programme (bloc BEGIN), tu peuples un tableau t, et chaque fois que tu rencontres NIR, tu enregistres à l'index courant (noté f) le nom du futur fichier.
      • Ensuite, tu traites le fichier à proprement parler, et à chaque fois que tu rencontres le mot PAGE, tu incrémentes un compteur (noté arbitrairement x) qui permet de récupérer dans t le nom du fichier.

      J'en profite pour corriger une petite erreur dans la proposition #1, car si le fichier ne s'appelle pas "fichier", ça ne marchera pas. Bref, voici à quoi peut ressembler mon_script.awk :

      #!/usr/bin/awk -f
      
      BEGIN {
          while (getline < ARGV[1]) {
              if ($0 ~ /NIR/) {
                  for (n = 1; n <= NF; n++) {
                      if ($n ~ /NIR/) {
                          t[++f] = $(n + 1)
                      }
                  }
              }
          }
      }
      
      /PAGE/ {
          a = t[++x] ".txt"
      }
      
      a {
          print $0 > a
      }

      Quelques remarques au passage :

      • Le premier if (0 ~ /NIR/) est superflu. En pratique, il n'apporte rien. En effet, ce test oblige en lui-même à lire la ligne courante, qu'on va relire une seconde fois dans la boucle for qui suit. Cela signifie qu'on lit deux fois les lignes contenant NIR et une fois les lignes ne contenant pas NIR. Si on supprime ce test, chaque ligne n'est lue qu'une fois.
      • Le bloc /PAGE/ permet de définir une variable a, qui correspond au fichier dans lequel on va écrire à présent. Si cette variable est définie, alors le 3e bloc est exécuté à chaque fois qu'on lit une nouvelle ligne, et il l'écrit dans le fichier a.

      Une fois le fichier mon_script.awk écrit, pour le lancer :

      awk -f mon_script.awk fichier.txt

      Ou encore, on donne les droits en exécution au script, et grâce à la première ligne du script, ton shell sera qu'il doit utiliser awk -f :

      chmod a+x mon_script.awk
      ./mon_script.awk fichier.txt

      Bonne chance

      0
    2. dubcek Messages postés 18627 Date d'inscription   Statut Contributeur Dernière intervention   5 660
       

      en awk, un tableau commence à 1 (pas à 0 comme en C, par ex.) et une variable indéfinie vaut 0
      à la première occurence de NIR f=0, donc t[++f] égale t[1], à la suivante t[2], etc
      on relit le fichier
      à la première occurence de PAGE x=0, donc t[++x] égale t[1], etc
      on relit le tableau t contenant le nom de fichier à créer

      0
  4. DIE
     

    merci à tous les deux, c'est très clair quand on vous lit mais très confus à sortir tout seul de ma tête ;)
    Manque de logique surement

    0