Le 18 mars 2010 à 15:23, Patrick Proniewski a écrit :
> On 16 mars 2010, at 19:13, Yvan KOENIG wrote:
>
>> Puis-je écrire que, comme la solution de patpro, pour le béotien
>> que je suis, c'est du cunéiforme ( je ne tiens pas à heurter un
>> utilisateur d'un langage encore vivant )?
>
> si on repart du script AWK dont je numérote les lignes :
>
> 1: #!/usr/bin/awk -F; -f
> 2: BEGIN { while ((getline < ficb) > 0)
> 3: fic2[$1]=$2}
> 4: {if (fic2[$1])
> 5: printf "%s%s%s\n",$1,FS,fic2[$1]
> 6: else
> 7: print $0}
>
> on peut expliquer les choses comme cela :
>
> À la ligne 1, on déclare l'interpréteur, et ses options : on veut
> que le contenu du script soit interprété par awk, avec les options
> -F; (séparateur = ";"), et -f indique que les lignes suivantes sont
> les instructions du script.
>
> Ligne 2, un BEGIN est déclaré. Cela permet de poser certaines
> variables, ou de faire des initialisations qui ne doivent être
> faites qu'une seule fois. Dans le cadre de ce BEGIN, on lit le
> fichier "ficb" ligne par ligne. C'est le code "(getline < ficb)".
> Tant qu'il y a des lignes (c'est le while), on exécute "fic2[$1]=
> $2" qui a pour fonction de créer un tableau qui s'appelle fic2 et
> qui associe l'intitulé contenu dans le champ 1 d'une ligne donnée
> ("[$1]") avec le contenu du champ 2 de la même ligne ("$2").
> Donc si une ligne du fichier est "toto";"titi", alors la valeur de
> fic2["toto"] sera "titi". C'est la ligne 3, l'accolade finale ferme
> le bloc BEGIN.
>
> En ligne 4, un if est ouvert, il teste "fic2[$1]". Attention, $1
> ici est le champ 1 d'une ligne du fichier "a" !
> Le script est exécuté en injectant les lignes du fichier "a" dans
> le programme awk. Dans le bloc BEGIN, on lit le fichier "b", mais
> les autres blocs du programme sont destinés à traiter les données
> injectées à partir de l'extérieur du script, ici la source est le
> fichier "a".
>
> Si "fic2[$1]" existe, donc si le tableau fic2 (créé à partir du
> fichier "b") un enregistrement existe, aillant pour index le
> premier champs de la ligne du fichier "a", alors (ligne 5) le
> script imprime en sortie la concaténation de $1, du séparateur ";"
> et du contenu de fic2[$1].
> Si il n'existe pas, alors (ligne 7) le script imprime en sortie la
> ligne du fichier "a", telle quelle.
>
> Une fois la ligne N du fichier "a" traitée, c'est au tour de la
> ligne N+1 de passer par les mêmes étapes (lignes 4 à 7).
>
> Je ne sais pas si j'ai clarifié les choses... :)
>
> Pour mon script à base de SQLite les explications sont peut être
> encore moins claires :) :
>
> 1: #!/bin/bash
> 2: # quelques definitions
> 3: MY_FILEDB=":memory:"
> 4: MY_SQLITE="/usr/bin/sqlite3"
> 5:
> 6: ${MY_SQLITE} "${MY_FILEDB}" <<EOF | sed 's,\([^|]*\)\|\([^|]*
> \),"\1";"\2",' > $3
> 7: CREATE TABLE file1(ref varchar(120),desc varchar(120));
> 8: CREATE TABLE file2(ref varchar(120),desc varchar(120));
> 9: $(sed 's/\([^;]*\);\([^;]*\)/INSERT INTO file1 VALUES(\1,
> \2);/' $1)
> 10: $(sed 's/\([^;]*\);\([^;]*\)/INSERT INTO file2 VALUES(\1,
> \2);/' $2)
> 11: SELECT file1.ref, IFNULL(file2.desc, file1.desc) FROM file1
> LEFT JOIN file2 ON file1.ref=file2.ref;
> 12: EOF
>
> Lignes 1 à 4, je défini l'interpréteur (bash), et deux variables.
> Les variables c'est un peu inutile ici. C'est bien pour les long
> scripts, ça permet de changer un élément du script à un seul
> endroit sans en chercher toutes les occurrences partout. Mais le
> script est trop court pour que ça soit utile ici.
>
> La ligne 6 est la plus complexe. Elle s'articule en 3 parties, et
> c'est à la fois la première vraie ligne de code, et la dernière !
> La première partie de la ligne 6 est la suivante :
> ${MY_SQLITE} "${MY_FILEDB}" <<EOF
> et correspond au code :
> /usr/bin/sqlite3 ":memory:" <<EOF
>
> Elle signifie : ouvre une base de donnée de type ":memory:" dans
> SQLite, et injecte lui toutes les lignes que tu liras ensuite,
> jusqu'à ce que tu trouves la chaîne "EOF".
> Cela me permet d'injecter dans SQLite plusieurs commandes à la
> suite des autres sans "lâcher" la base de données. Comme je
> travaille en ":memory:", il ne faut pas que j'interrompe ma
> transaction avec la base de données, sinon elle disparait
> définitivement (c'est le propre des bases de données temporaires
> stockées en RAM).
> Voyons les lignes 7 à 12 avant de remonter à la ligne 6.
>
> Les lignes 7 et 8 créent simplement chacune une table (file1 et
> file2), avec les champs "ref" et "desc", en texte, sur 120
> caractères de long.
> Les lignes 9 et 10 disent à bash d'exécuter respectivement :
> sed 's/\([^;]*\);\([^;]*\)/INSERT INTO file1 VALUES(\1,\2);/' $1
> et sed 's/\([^;]*\);\([^;]*\)/INSERT INTO file1 VALUES(\1,\2);/' $2
> $1 et $2 sont les deux premiers arguments passés au script
> (script.sh arg1 arg2 arg3). Ils sont sensés être les chemins du
> fichier A et du fichier B.
> ces lignes disent à sed de remplacer pour chaque ligne des fichiers
> A et B les occurences de référence;description par le code SQL
> "INSERT INTO file1 VALUES(référence,description);"
> Comme les commandes sed sont encapsulées dans $( ) et bien le
> résultat de chaque commande sed remplace le contenu des lignes 9 et
> 10. Donc SQLite reçoit directement les INSERT, de la même manière
> qu'il a reçu les CREATE TABLE.
>
> Enfin, la ligne 11 fait la recherche SQL qui répond au problème
> initial, à savoir faire la synthèse des fichiers A et B. La
> commande joint les deux fichiers en s'appuyant sur le critère
> d'identité des références, et elle affiche la référence du
> fichier A, la description correspondante dans le fichier B si elle
> existe, et la description correspondante du fichier A si celle du
> fichier B n'existe pas.
>
> La ligne 12 indique à bash qu'il n'y a plus de ligne à injecter
> dans le "<<" (HERE DOCUMENT). On revient donc à la ligne 3.
>
> La seconde partie de la ligne 3 est :
> | sed 's,\([^|]*\)\|\([^|]*\),"\1";"\2",'
> Le "pipe" reçoit la sortie de la commande SQLite (le résultat du
> SELECT de la ligne 11) , et l'injecte dans le sed.
> La commande sed prend le résultat :
> référence|description
> et le transforme en :
> "référence";"description"
>
> J'aurai pu remplacer le sed par un SELECT mieux ficelé, mais j'ai
> eu la flemme.
>
> La fin de la ligne 3 "> $3" injecte la sortie du sed dans le
> fichier dont le chemin est précisé par le 3ème argument au
> lancement du script.
>
>
> patpro
Merzi.
Je zuis enrhubé zi bien que je n'ai pas les idées bien glaires.
Je grois avoir gobris les exbligazions du zgribt awk.
Bour l'audre je grois qu'il vaudra addendre un beu ;-)
Yvan KOENIG (VALLAURIS, France) jeudi 18 mars 2010 16:18:27
heureusebent gue z'ai un zcribt bour inzérer ba zignadure.
_______________________________________________
archives :
http://listes.patpro.net/list/sshfr.fr.html
http://listes.patpro.net/mailman/listinfo/script_shell_fr