[awk] découper un fichier en plusieurs fichiers

Résolu
DIE - Modifié le 14 févr. 2024 à 15:32
 DIE - 16 févr. 2024 à 17:24

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

A voir également:

4 réponses

dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
14 févr. 2024 à 13:13

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
mamiemando Messages postés 33081 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 27 avril 2024 7 749
14 févr. 2024 à 15:35

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

bjr mamiemando,

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

0

ç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
mamiemando Messages postés 33081 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 27 avril 2024 7 749
Modifié le 15 févr. 2024 à 10:35

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
dubcek Messages postés 18718 Date d'inscription lundi 15 janvier 2007 Statut Contributeur Dernière intervention 22 mars 2024 5 615
15 févr. 2024 à 11:01

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

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