Sed/awk pour lier 2 fichier plats

[Résolu/Fermé]
Signaler
-
Messages postés
18304
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
26 octobre 2021
-
Bonjour,

Je débute en shell et on me confie un probleme qui ne semble pas avoir été posé ici. Il s'agit de lier deux fichiers texte représentant à eux deux, la structure d'une base de données(les tables, seulement).

Sur le premier (fichier1), j'ai
tab01999999champ19999AAA999
tab01999999champ29999AAA999
tab01999999champ39999AAA999
tab02999999champ19999AAA999
tab02999999champ29999AAA999
...


* Les 5 premier caractères correspondent au nom de la table (longueur fixe)
* Les champs sont écrits sur 6 caractères à partir de la colonne 11 (longueur fixe)
* Le reste (AAA, 999) sont des valeurs alphanumériques variables

Le second (fichier2) ?une forme un peu plus claire :
AAA;;tab01;;champ2;;N;;05;;999;;AAA;;999
AAA;;tab01;;champ1;;D;;08;;999;;AAA;;999
AAA;;tab02;;champ2;;N;;05;;999;;AAA;;999
AAA;;tab02;;champ1;;D;;08;;999;;AAA;;999
AAA;;tab01;;champ3;;C;;50;;999;;AAA;;999
AAA;;tab01;;champ4;;N;;05;;999;;AAA;;999
...


* Les séparateurs sont un peu tordus
* On récupere des informations sur le type des champs (N=Number, D=Date, C=Char)
* On récupere des informations sur la taille des champs (05, 08, 50 ...)
* Le fichier n'est pas trié / ordonné
* Le fichier présente des champs obsolètes (Tab01.champ4, par exemple)
* Les AAA et 999 sont toujours des valeurs alphanumériques variables


On me demande de récupérer les informations de chaque fichier afin de créer des requêtes sql "CREATE TABLE". Par exemple :
CREATE TABLE tab01 (champ1 Date (08), champ2 Number (05), champ3 Char (50));


Je n'aurai pas trop de problème dans un autre langage mais on ne me laisse pas d'autre
choix que le script unix, dans lequel (et en dépit des tutos de jipicy) je reste débutant.

J'ai pensé commencer par un awk pour pouvoir mettre un programme (avec des boucles) derrière mais je suis de toute façon bloqué par l'entrée en jeu du second fichier. Je suis comme devant un puzzle et je n'arrive pas ?trouver de coin :(

Si vous pouviez assortir vos réponses de quelques explications (cheminement logique), ça m'éviterai peut être de venir vous rembeter par la suite. Merci.

5 réponses

Messages postés
18304
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
26 octobre 2021
5 416
hello
un p'tit coup de awk
$ cat f1.awk
BEGIN {a["D"]="Date";a["N"]="Number";a["C"]="Char"}
NF < 2 { x[substr($0,1,5), substr($0,12,6)]=1}
NF > 2 && x[$3,$5] {y[$3]=y[$3] $5 " " a[$7] " ("$9"), "}
END {for (n in y){sub(", $","",y[n]);print "CREATE TABLE",n,"(" y[n] ");"}}

$ 
$ (cat fichier1 ; sort -t ";" -k 3 fichier2 ) | awk -F ";" -f f1.awk
CREATE TABLE tab01 (champ1 Date (08), champ2 Number (05), champ3 Char (50));
CREATE TABLE tab02 (champ1 Date (08), champ2 Number (05));
$ 
3
Merci

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

CCM 41989 internautes nous ont dit merci ce mois-ci

Messages postés
18304
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
26 octobre 2021
5 416
le post reste ouvet, pose tes questions
si le sort n'est pas utile, alors la commande peut se faire comme ça:
awk -F ";" -f f1.awk fichier1 fichier2
Bonjour,
Je reviens sur ce probleme après avoir été occupé sur un autre ailleurs. Je me concentre encore une fois sur l'ordre d'execution du script.
la commande awk -F ";" -f f1.awk fichier1 fichier2 me semble etre la meilleure.

Si je comprends bien, c'est le suivant :
BEGIN { on cree un tableau d'équivalence }
On lit tout le premier fichie en notant à VRAI les couples (table, champs) dans un tableau x
On lit tout le fichier 2 et pour chaque couple (table, champs) à vrai, on écrtit dans un tableau y les informations : y[table] = y[table] + information du nouveau champs
END Pour chaque cellule du tableau y (donc pour chaque table), on écrit "CREATE TABLE" ...


Dans ce cas, on enregistre (dans le tableau y) les informations des champs dans l'ordre du fichier 2 (au fur et à mesure de sa lecture).

Je voudrais que les informations soient enregistrée dans l'ordre du fichier 1. Ca m'a amené à reécrire la fonction awk ainsi :
BEGIN {a["D"]="Date";a["9"]="Number";a["X"]="Char"} 
NF > 2 { x[$3,$5]=1 ; y[$3]=y[$3] $5 " " a[$7] " ("$9"), "} 
NF < 2 && x[substr($0,1,5), substr($0,12,6)] {z[substr($0,1,4)] = z[substr($0,1,4)] y[$3]} 
END {for (n in z){sub(", $","",z[n]);print "CREATE TABLE",n,"(" z[n] ");"}}


Mais cela ne fonctionne pas et je ne vois pas pourquoi.
Pourriez vous encore m'aider svp ?
Messages postés
18304
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
26 octobre 2021
5 416
$ awk -F ";" -f f1.awk fichier2 fichier1
CREATE TABLE tab01 (champ1 Date (08), champ2 Number (05), champ3 Char (50));
CREATE TABLE tab02 (champ1 Date (08), champ2 Number (05));
$
$ head f1.awk
BEGIN {a["D"]="Date";a["N"]="Number";a["C"]="Char"}
NF > 2 { x[$3,$5]=$0 }
NF < 2 { t=substr($0,1,5); c=substr($0,12,6) ; if(x[t,c]){ split(x[t,c], b) ; y[t]=y[t] b[5] " " a[b[7]] " ("b[9]"), "} }
END {for (n in y ){sub(", $","",y[n]);print "CREATE TABLE",n,"(" y[n] ");"}}

description
BEGIN {a["D"]="Date";a["N"]="Number";a["C"]="Char"}
on crée un tableau a[] contenant le titre des champs, plus simple pour les afficher que faire des if
NF > 2 { x[$3,$5]=$0 }
pour le fichier 2, on stocke chaque ligne dans un tableau x[] indexé tabXX,champY
NF < 2 { t=substr($0,1,5); c=substr($0,12,6) ; if(x[t,c]){ split(x[t,c], b) ; y[t]=y[t] b[5] " " a[b[7]] " ("b[9]"), "} }
pour le fichier 1, on assigne t=tabXX, c=champY, on teste si x[t,c] existe, donc existe dans le fichier 2; avec split on recupère la ligne de fichier 2 dans le tableau b[], donc b[n] = champ n ($n), et on concatène les valeurs dans le tableau y[], indexé par tabXX, selon l'ordre de fichier 1
END {for (n in y ){sub(", $","",y[n]);print "CREATE TABLE",n,"(" y[n] ");"}}
on affiche le contenu du tableau y[] en supprimant la dernière virgule avec sub
Ah ! Zut ... j'étais pas si loin (d'ailleurs, je ne vois toujours pas mon erreur. Mais ce n'est pas si grave face à une réponse aussi complete).
Je n'avais pas pensé qu'on pouvais faire un if x[t,c] ... c'est une excelente idée, même si elle n'est pas utilisable partout.
En plus c'est tellement clair que je peux facilement l'adapter pour faire tout ce que je veux. J'espere pouvoir faire aussi bien, un jour. Merci beaucoup, dubcek, pour cette réponse/leçon.
Messages postés
18304
Date d'inscription
lundi 15 janvier 2007
Statut
Contributeur
Dernière intervention
26 octobre 2021
5 416
on pourrait aussi faire
NF < 2 && (x[t=substr($0,1,5), c=substr($0,12,6)]) { split(x[t,c], b) ; y[t]=y[t] b[5] " " a[b[7]] " ("b[9]"), " }

&& (x[t=substr($0,1,5), c=substr($0,12,6)])
on assigne t et c et on teste le contenu de x[t,c]
Messages postés
40805
Date d'inscription
jeudi 28 août 2003
Statut
Modérateur
Dernière intervention
10 août 2020
4 888
Salut,

J'ai du mal à comprendre le rapport qui existe entre le fichier1 et le fichier2 !!??

Quels sont les critères qui unissent les 2 fichiers dans la requête à fournir ?

Si on s'en réfère à ton exemple, seul le fichier2 est utile pour écrire la requête, non ?

Bonjour jipicy,

le fichier #1 permet de savoir quels enregistrements du fichier #2 sélectionner : tab01.champ4 n'apparaît pas dans le fichier #1, il ne faut pas le retenir du fichier #2.
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 562
Salut,

Ca sera pas plus facile de donner un exemple concret en utilisant tes fichiers?
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 562
Re,

Si j'ai bien compris, par exemple si on prends la tab02 tu dois obtenir

CREATE TABLE tab02 (champ1 Date( 08), champ2 Number (05));

?!
Utilisateur anonyme
C'est tout à fait ça, lami20j.
Et j'ai évité de donner un exemple "réèl" parce que les noms des tables / champs sont en fait des codes alphanumeriques beaucoup moins compréhensibles que tab01 ou champ3.
(pour donner l'exemple que j'ai sous les yeux : table TR35B)

c'est ce qu'à fait nnj99

Merci de répondre si vite.
Comme le dit qqchquicommenceparQ, le fichier 1 possede les tables, les champs et "l'ordre" dans/avec/pour (?) lequel on me demande de créér les champs.

Il est lié au fichier 2 (qui lui possède tout) par les informations "table" et "champs".
Dans le fichier 1, la table correspond au 5 premiers carracteres (donc je pense que que j'aurai un "cut -c0-5" quelque part), dans le fichier 2 c'est le deuxieme "champs" - ou du caractere 5 au carractere 10, puisqu'il n'y a pas qu'une façon de résoudre.A
Concernant les champs, on le trouve du carractere 11 à 16 pour le fichier 1 et en 3ème colonne dans le fichier 2.