Bonjour
Je cherche des idées pour améliorer (rapidité d'exécution) mon script bash . Il permet de traiter de gros fichiers. Avez vous des idées?
Le code
Merci
Tio
Version imprimable
Bonjour
Je cherche des idées pour améliorer (rapidité d'exécution) mon script bash . Il permet de traiter de gros fichiers. Avez vous des idées?
Le code
Merci
Tio
Bonjour Tio,
Tu peux ne pas utiliser :Citation:
Envoyé par Tiolebucheron
echo devant les variables du style ${line:n:m}
echo $var | sed, mais sed <<<"$var" (qui ne sont d'ailleurs pas indispensables, des remplacements de paramètres successifs de la même variable
une seule instance de sed : sed 's/anc/nouv/; s/anc2/nouv2/'
awk | sed : c'est soit awk soit sed, mais pas les deux
bc pour calculer des entiers
::
bref, limiter au strict minimum l'utilisation de programmes externes.
-
les tests depuis $l1 jusqu'à $ville, peuvent réaliser dans une boucle for. Ça ne fera pas ganer de temps mais de l'espace...
-
une petite question : à quoi servent tous ces guillemets ?
Oui en effet il y a matière a améliorer. Mes cours de shel remonte à 10 ans maintenant, un peu rouillé le gars.
Pour les guillemets une fois qu'une commande fonctionne j'ai reporté la même chose partout. par contre j'ai par trop compris l'histoire du for!!!
Je serai a mon bureau dans une heure je fais dejà les premières modifications et reposte le nouveau code.
MErci pour l'aide
tio
Le test [ -z "$ville" ] || [ "$ville" = "" ] fait 2 appels. Il vaut mieux le remplacer par un connecteur OR interne => [ -z "$ville" -o "$ville" = "" ]
Toutetois c'est inutile vu que l'option -z teste variable vide donc l'égalité avec rien est implicite => [ -z "$ville" ] est bien suffisant
Effectivement tous ces guillemets sont inutiles => ville="'$ville'" marche parfaitement
Moi on plus. Peut-être un for x in `cat fichier` mais personnellement j'apprécie pas trop cette syntaxe car si le fichier contient des espaces dans ses mots, le for traitera chaque mot avec comme 2 éléments séparés. Je préfère de loin la syntaxe cat fichier |while read x
Re,
Je rencontre des difficultés pour enlever l'echo de cet commande
majic3=$(echo "${line:18:6}" | sed -e 's/[[:blank:]]*$//')
Pouvez-vous m'aider?
Merci
PS : 2 seconde de gagner déjà (sur un test de 80 lignes traitées)
Oui Merci pour vos réponse mais les espaces à supprimer sont à la fin de la chaine de caractère, ce n'est pas l'ensemble des espaces.
Un autre exemple
Merci de votre aideCode:
1
2
3 nom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $1}' | sed -e "s/'/''/g") prenom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $2}') prenom=$(echo "$prenom" | sed -e 's/[[:blank:]]*$//' | sed -e "s/'/''/g")
Peut être remplacé parCode:
1
2
3
4
5
6 cpt=$(echo "($cpt + $un)" | bc) if [ "$(echo "($cpt % $cent)" | bc)" = 0 ] then END=$(date +%s) tps_execution fi
Apparemment, le script fait beaucoup de mise en forme ; je pense que la comande printf pourrait faire une bonne part du boulot.Code:
1
2 ((cpt+=$un)) ((cpt%$cent)) || { END=$(date +%s); tps_execution; }
Merci on est descendu en dessous des 4 secondes. contre 8 au départ.
Le code
Je vous met une nouvelle version
Je blocque toujours sur
Pour le mettre avec un seul sed.Code:#dnomcp=$(echo "${line:405:30}" | sed -e 's/[[:blank:]]*$//' | sed -e "s/'/''/g")
Merc à tous de votre aide.
Code:
1
2
3 dnomcp=$(echo "${line:405:30}" | sed -e 's/[[:blank:]]*$//' | sed -e "s/'/''/g") # Devient : dnomcp=$(echo "${line:405:30}" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g")
Si le nom contient une apostrophe, le sed pose problème ! (pour N'Guyen, par exemple), Sinon on peut éviter l'appel à awk avec :Code:nom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $1}' | sed -e "s/'/''/g")
puis :Code:nom=${line:56:60}; nom=${nom%/*}
Sinon, quel est le but deCode:
1
2
3 prenom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $2}') # devient prenom="${line:56:60}"; prenom=${nom#*/}
Ce serait intéressant à contournerCode:sed -e "s/'/''/g"
Le code
Merci Encore une seconde de gagner. (8=>3)
Avez vous d'autre idées? Merci de votre au final je vais gagner quelque heure de traitement de fichier.
Tio
Ça pourrait être intéressant de poster quelques lignes du fichier source et le résultat escompté.
Citation:
140001D00110014421MB2TCLP 112 DE BREVEDENT D ABLON/ARLETTE JEANNE ALBERTE MARIE 9792 LE CHATEAU 14600 ABLON 14 14600 MMECLERET DE LANGAVANT MICHEL 09/03/193214 ABLON NEEDE BREVEDENT D ABLON ARLETTE JEANNE 11 100064108063A 1404421
140001D00111014421MB2TCLPI112 DE BREVEDENT D ABLON/ARLETTE JEANNE ALBERTE MARIE 9792 LE CHATEAU 14600 ABLON 14 14600 MMECLERET DE LANGAVANT MICHEL 09/03/193214 ABLON NEEDE BREVEDENT D ABLON ARLETTE JEANNE 11 100064108063A 1404421
140001D00111024421MB2TCQPI011 CLERET DE LANGAVANT/OLIVIER RAPHAEL MARIE 9292 0006 RUE TOULLIER 75005 PARIS 7581050021293550006 75005 M CLERET DE LANGAVANT OLIVIER RAPHAEL10/02/195714 DEAUVILLE 11 100054343789A 1404421
C'est assez trivial, l'objet est de saisir une base de données; Mon script pour le lancement sql est déjà optimisé.Citation:
SET DATEFORMAT DMY;
INSERT INTO [TESTCad_NORM09].[dbo].[Personnes] ([Majic3_Code], [Civilite_Code],[Nom],[Prenom],[Representant],[AdresseL1],[AdresseL2],[AdresseL3],[CodePostal],[Commune_Nom],[Pays_Code],[Adresse_Exacte],[DateNaissance],[NomEpx] ,[PrenomEpx] ,[FrmJur_Code] ,[CRPF_ID] ,[DateCreation] ,[DateModification] ,[AuteurCreation] ,[AuteurModification] ,[tmpClePropri]) VALUES ('MB2TCL','MME','DE BREVEDENT D ABLON','ARLETTE JEANNE ALBERTE MARIE',NULL,'LE CHATEAU',NULL,NULL,'14600','ABLON','F',1,cast('09/03/1932 00:00:00' AS DATETIME),NULL,NULL,'P',14,CURRENT_TIMESTAMP,NULL,'RL',NULL,NULL);
INSERT INTO [TESTCad_NORM09].[dbo].[Personnes] ([Majic3_Code], [Civilite_Code],[Nom],[Prenom],[Representant],[AdresseL1],[AdresseL2],[AdresseL3],[CodePostal],[Commune_Nom],[Pays_Code],[Adresse_Exacte],[DateNaissance],[NomEpx] ,[PrenomEpx] ,[FrmJur_Code] ,[CRPF_ID] ,[DateCreation] ,[DateModification] ,[AuteurCreation] ,[AuteurModification] ,[tmpClePropri]) VALUES ('MB2TCL','MME','DE BREVEDENT D ABLON','ARLETTE JEANNE ALBERTE MARIE',NULL,'LE CHATEAU',NULL,NULL,'14600','ABLON','F',1,cast('09/03/1932 00:00:00' AS DATETIME),NULL,NULL,'P',14,CURRENT_TIMESTAMP,NULL,'RL',NULL,NULL);
INSERT INTO [TESTCad_NORM09].[dbo].[Personnes] ([Majic3_Code], [Civilite_Code],[Nom],[Prenom],[Representant],[AdresseL1],[AdresseL2],[AdresseL3],[CodePostal],[Commune_Nom],[Pays_Code],[Adresse_Exacte],[DateNaissance],[NomEpx] ,[PrenomEpx] ,[FrmJur_Code] ,[CRPF_ID] ,[DateCreation] ,[DateModification] ,[AuteurCreation] ,[AuteurModification] ,[tmpClePropri]) VALUES ('MB2TCQ','M','CLERET DE LANGAVANT','OLIVIER RAPHAEL MARIE',NULL,'0006 RUE TOULLIER',NULL,NULL,'75005','PARIS','F',1,cast('10/02/1957 00:00:00' AS DATETIME),NULL,NULL,'P',14,CURRENT_TIMESTAMP,NULL,'RL',NULL,NULL);
Citation:
Envoyé par Tiolebucheron
Ça fait le même chose, mais tient sur une ligne.Code:for var in l2 l3 pc ville; do [ -z ${!var} ] && eval $var="NULL"; done
Il faut absolument éviter les appels à awk car c'est hyper gourmand (ou alors on fait tout le traitement avec un seul awk)
Et donc on peut remplacer
ParCode:nom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $1}')
Code:nom=$(echo "${line:56:60}" | cut -d/ -f1)
Moins important mais à ne pas négliger: on peut aussi remplacer
Code:
1
2
3
4
5
6
7
8
9
10
11 if [ "$frmjur" = " " ] then frmjur="'P'" else if [ -z "$frmjur" ] then frmjur="NULL" else frmjur="'$frmjur'" fi fi
par
Code:
1
2
3
4
5
6
7
8
9 if [ "$frmjur" = " " ] then frmjur="'P'" elif [ -z "$frmjur" ] then frmjur="NULL" else frmjur="'$frmjur'" fi
Remplacer des conditions enchainées avec "||" par des "-o"
=> un seul appel à test au lieu de 3Code:if [ -z "$naissance" -o "$naissance" = " " -o "$naissance" = "00/00/0000" ]
Et (je l'ai raté mais j'aurais dû le dire hier) on peut remplacer chaque test simple, comme celui-ci
Code:
1
2
3
4
5
6 if [ -z "$ville" ] then ville="NULL" else ville="'$ville'" fi
Par un test encore plus simple
Code:[ -z "$ville" ] && ville="NULL" || ville="'$ville'"
Et ptet essayer de gagner en lisibilité en le mettant dans le sens logique
Car il semble naturel d'espérer plus de présences que d'abscences.Code:[ -n "$ville" ] && ville="'$ville'" || ville="NULL"
Maintenant, on peut aussi envisager un changement radical en réécrivant tout le script en Python. La première fois que j'ai essayé, j'avais un script shell qui convertissais un gros fichier texte en fichier XML. Ca marchait mais le script mettait 30mn pour tout parser.
Je l'ai réécrit en Python => le traitement a duré moins de 2mn. Ce jour là, je me suis mis définitivement à Python...
J'ai lu en diagonale. S'il s'agit bien de parser un fichier à champs de longueur fixe, GNU awk dispose d'une variable builtin particulièrement efficace pour ce genre de problème.
http://www.gnu.org/software/gawk/man...#Constant-Size
Ça sera plus efficace que de traverser un fichier avec un read.
Merci pour tous ces renseignements
Pour la dernière fonction c'est trop compliqué pour moi et pour python encore plus et pas trop le temps
Encore un renseignement
Je cherche à tester la chaine de caractère contenant la date. exemple '12/12/1979". Il y a des dates erronées 30/02/1930 ou encore 00/00/1950.
Existe-il un format date en bash permettant de tester?
Merci de votre aide
Tio
Si j'ai le temps cet aprem je te porterai ton script et tu verras la simplicité
Désolé, le bash ne connait que le texte. Si tu veux tester, il te faut faire une fonction adaptée
Exemple de fonction qui décompose une chaine jj/mm/aaaa
Code:
1
2
3
4
5
6
7
8 verifDate() { jj=`echo $1 |cut -d/ -f1` mm=`echo $1 |cut -d/ -f2` aa=`echo $1 |cut -d/ -f3` # Plus qu'à vérifier la validité de $jj, $mm et $aa }
En bash non mais il faut voir la fonction date si elle accepte l'option -d ou --date. (faire 'man date'). Si la date est fausse, la fonction retourne une erreur, la syntaxe serait alors :
Code:
1
2
3
4
5
6 if date -d "$DATE" >/dev/null # pour éviter tout affichage then echo "date correcte" else echo "date incorrecte" fi
Bonjour
Je vais regarder mais c'est une bonne idée
Il y a un souci le format est Mois jour année.Code:
1
2
3
4
5
6
7 tiolebucheron@debianSite:~/test$ date lundi 1 février 2010, 13:15:12 (UTC+0100) tiolebucheron@debianSite:~/test$ date -d "12/12/1979" mercredi 12 décembre 1979, 00:00:00 (UTC+0100) tiolebucheron@debianSite:~/test$ date -d "12/00/1979" date: date invalide `12/00/1979' tiolebucheron@debianSite:~/test$
Il faut que je décompose la chaine qd même le date -d permettra au mois de tester
Hello,
Si tu es sûr du format de la date:
Code:
1
2
3
4 #variable dd/mm/yyyy date="15/02/1980" date --date=${date:3:2}/${date:0:2}/${date:6:4}
Voila la conclusion Pour une date 00/00/1978 par défaut elle sera mise au 01/01/1978.Code:
1
2
3
4
5
6
7
8
9
10
11
12 if date -d "${naissance:3:2}/${naissance:0:2}/${naissance:6:4}" > /dev/null then naissance="cast('$naissance 00:00:00' AS DATETIME)" else if [ -z "$naissance" -o "${naissance:6:4}" = "0000" ] then naissance="NULL" else naissance="cast('01/01/${naissance:6:4} 00:00:00' AS DATETIME)" fi fi echo $naissance
Par contre le > /dev/null servant à supprimer l'affichage ne fonctionne pas.
Merci à tous.
tio
c'est parce que la commande redirige vers la sortie d'erreur dans le cas d'une date invalide
En redirigant le flux de sortie d'erreur vers le flux standard qui redirige déja vers /dev/null plus rien ne passe ;)
Code:date -d "${naissance:3:2}/${naissance:0:2}/${naissance:6:4}" > /dev/null 2>&1
Merci cela fonctionne très bien.
J'ai porté ton script en Python ce qui s'est fait sans difficulté (sauf que je suis pas sûr des positions car elles ne semblent pas trop coller avec l'exemple que t'as donné récemment)
Sinon ça m'a permis de détecter une instruction qu'on peut alléger
Code:if [ "$(echo "${gtyp:1:2}")" = "88" ]
Ce qui évite un appel inutile à un sous-process. D'ailleurs dans 99% des cas, si on fait $(echo "qqchose)", ça peut se remplacer par "qqchose"Code:if [ "${gtyp:1:2}" = "88" ]
C'est con, j'ai oublié mon script python au bureau. Je récupère ton nouveau script ce soir et demain je t'amène son équivalent Python.
Je suis par ailleurs resté assez embêté sur ce bloc
Etant donné que frmjur récupère un caractère à la position 37, il ne pourra jamais être vide donc le test -z ne sera jamais validé. A vérifier...Code:
1
2
3
4
5
6
7
8
9
10
11 frmjur=${line:37:1} ... if [ "$frmjur" = " " ] then frmjur="'P'" elif [ -z "$frmjur" ] then frmjur="NULL" else frmjur="'$frmjur'" fi
[edit] Vu que personne n'est intervenu, je reprends et continue ce post
J'ai donc porté ton script en Python. Voici d'abord le script originel tel que je l'ai trouvé sur le site dont t'as parlé (au fait, pourquoi le mettre là bas et pas ici ???) - Je lui ai juste enlevé ses chronos internes (inutiles vu qu'il existe la commande "time") et son affichage final
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 #!/bin/bash while read line do dept=${line:0:2} frmjur=${line:37:1} naissance=${line:334:10} expnee=${line:402:3} pays=${line:248:3} gtyp3=${line:116:1} gtyp4=${line:117:1} gtyp5=${line:118:1} gtyp6=${line:119:1} gtyp=${line:116:4} dlign3=${line:120:30} dlign4=${line:150:36} dlign5=${line:186:30} dlign6=${line:216:32} l1="";l2="";l3="";cp="";ville=""; nom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $1}' | sed -e "s/'/''/g") prenom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $2}') prenom=$(echo "$prenom" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") civilite=$(echo "${line:286:3}" | sed -e 's/[[:blank:]]*$//') majic3=${line:18:6}; majic3=${majic3%% *} if [ -z "$naissance" ] || [ "$naissance" = " " ] || [ "$naissance" = "00/00/0000" ] then naissance="NULL" else naissance="cast('$naissance 00:00:00' AS DATETIME)" fi if [ "$frmjur" = " " ] then frmjur="'P'" else if [ -z "$frmjur" ] then frmjur="NULL" else frmjur="'$frmjur'" fi fi if [ "$expnee" = "EPX" ] then dnomcp="'$(echo "${line:405:30}" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g")'" dprncp="'$(echo "${line:435:15}" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g")'" else dnomcp="NULL" dprncp="NULL" fi if [ "$pays" = " " ];then pays="F";fi if [ "$(echo "${gtyp:1:2}")" = "88" ] then if [ "$(echo "${gtyp:0:1}")" = "2" ] then l1=$(echo "$dlign3" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") fi l2=$(echo "$dlign4" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") l3=$(echo "$dlign5" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") else if [ "$gtyp3" = "2" ] then l1=$(echo "$dlign3" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") l2=$(echo "$dlign4" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") l3=$(echo "$dlign5" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") else l1=$(echo "$dlign4" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") l2=$(echo "$dlign5" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") fi cp=$(echo "${dlign6:0:5}") ville=$(echo "${dlign6:6:26}" | sed -e 's/[[:blank:]]*$//' -e "s/'/''/g") fi if [ -z "$l1" ]; then l1="NULL";else l1="'$l1'"; fi if [ -z "$l2" ] then l2="NULL" else l2="'$l2'" fi if [ -z "$l3" ] then l3="NULL" else l3="'$l3'" fi if [ -z "$cp" ] then cp="NULL" else cp="'$cp'" fi if [ -z "$ville" ] then ville="NULL" else ville="'$ville'" fi echo "'$majic3','$civilite','$nom','$prenom',NULL,$l1,$l2,$l3,$cp,$ville,'$pays',1,$naissance,$dnomcp,$dprncp,$frmjur,$dept,CURRENT_TIMESTAMP,NULL,'RL',NULL,NULL);" done < PROP14001
Et voici son équivalent Python.
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 #!/usr/bin/env python # coding: UTF-8 -*- import sys # Gestion système import datetime # Gestion des dates # Fonction de vérification de date def isDate( dateTxt): # Si la date est incorrecte, il y aura une levée d'exception try: # Extraction jj/mm/aaaa jj=int(dateTxt[0:2]) mm=int(dateTxt[3:5]) aa=int(dateTxt[6:10]) # Création d'une date avec aa, mm et jj datetime.date(aa, mm, jj) # Si exception except ValueError: # La date entrée n'est pas valide return False # try # La date entrée est valide return True # isDate() # Ouverture fichier try: fp=open("PROP14001", "r") except IOError: print "Impossible d'ouvrir PROP14001 - Abandon" sys.exit(1) # try # Traitement fichier PROP14001 for lig in fp: # Suppression '\n' de fin de ligne if lig[-1] == "\n": lig=lig[0:-1] # Extraction des infos dept=lig[0:2] frmjur=lig[37] naissance=lig[334:344] expnee=lig[402:405] pays=lig[248:251] gtyp3=lig[116] gtyp4=lig[117] gtyp5=lig[118] gtyp6=lig[119] gtyp=lig[116:120] dlign3=lig[120:150] dlign4=lig[150:186] dlign5=lig[186:216] dlign6=lig[216:248] l1="" l2="" l3="" cp="" ville="" nom_prenom=lig[56:116].split("/") nom=nom_prenom[0].strip().replace("'", "''") prenom=len(nom_prenom) >=2\ and nom_prenom[1].strip().replace("'", "''")\ or "" civilite=lig[286:289].strip() majic3=lig[18:24].strip() # Analyse des infos naissance=isDate(naissance)\ and ("cast('%s 00:00:00' AS DATETIME)" % naissance)\ or "NULL" frmjur="'%s'" % (frmjur == " " and "P" or frmjur) if expnee == "EXP": dnomcp=lig[405:435].strip().replace("'", "''") dprncp=lig[435:450].strip().replace("'", "''") else: dnomcp="NULL" dprncp="NULL" # if if pays == " ": pays="F" if gtyp[1:3] == "88": if gtyp[0] == "2": l1=dlign3.strip().replace("'", "''") l2=dlign4.strip().replace("'", "''") l3=dlign5.strip().replace("'", "''") else: if gtyp3 == "2": l1=dlign3.strip().replace("'", "''") l2=dlign4.strip().replace("'", "''") l3=dlign5.strip().replace("'", "''") else: l1=dlign4.strip().replace("'", "''") l2=dlign5.strip().replace("'", "''") # if # if cp=dlign6[0:5] ville=dlign6[6:32].strip().replace("'", "''") l1=l1 != "" and ("'%s'" % l1) or "NULL" l2=l2 != "" and ("'%s'" % l2) or "NULL" l3=l3 != "" and ("'%s'" % l3) or "NULL" cp=cp != "" and ("'%s'" % cp) or "NULL" ville=ville != "" and ("'%s'" % ville) or "NULL" print "'%s','%s','%s','%s',NULL,%s,%s,%s,%s,%s,'%s',1,%s,%s,%s,%s,%s,CURRENT_TIMESTAMP,NULL,'RL',NULL,NULL);" % ( majic3, civilite, nom, prenom, l1, l2, l3, cp, ville, pays, naissance, dnomcp, dprncp, frmjur, dept, ) # for # Fermeture fichier fp.close()
Déjà, tu verras que ce n'est franchement pas trop différent (à ce niveau), de ton script shell. Juste var[deb:fin] au lieu de var{deb:nb_car} (à noter que sous Python, on peut indicer un tableau en partant de la fin en utilisant -1, -2, -3 etc et demander des plages comme du début jusqu'à la fin (non incluse donc en fait jusqu'à l'avant dernier) en indiquant tab[0:-1] ce qui est assez pratique) et l'utilisation de méthodes de traitement de chaines intégrées à l'objet "str" qui caractérise toute chaine Python. Bien sûr, il faut savoir que ces méthodes existent mais avec un bon tuto, ou même l'aide en ligne de Python, ça va assez vite.
Mais la grosse différence, ce sera la rapidité de traitement. Je te laisse tester...
Je suis en réunion ce matin, Je test au plus vite.
Merci du temps passé.
Je reprend le post.
Merci C'est phénoménal, cela vaut le coup de se pencher sur python en effet traitement de 1000 ligne 69 sec à rien). Merci pour l'aide apportée.
Je suis arrivé à cela
Par contre, j'ai l'erreur suivanteCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151 #!/usr/bin/env python # coding: UTF-8 -*- import sys # Gestion système import datetime # Gestion des dates # Fonction de vérification de date def isDate( dateTxt): # Si la date est incorrecte, il y aura une levée d'exception try: # Extraction jj/mm/aaaa jj=int(dateTxt[0:2]) mm=int(dateTxt[3:5]) aa=int(dateTxt[6:10]) # Création d'une date avec aa, mm et jj datetime.date(aa, mm, jj) # Si exception except ValueError: # La date entrée n'est pas valide return False # try # La date entrée est valide return True # isDate() # Ouverture fichier try: fp=open("PROP14001", "r") except IOError: print "Impossible d'ouvrir PROP14001 - Abandon" sys.exit(1) # try # Traitement fichier PROP14001 for lig in fp: # Suppression '\n' de fin de ligne if lig[-1] == "\n": lig=lig[0:-1] # Extraction des infos dept=lig[0:2] frmjur=lig[37] naissance=lig[334:344] expnee=lig[402:405] pays=lig[248:251] gtyp3=lig[116] gtyp=lig[116:120] dlign3=lig[120:150] dlign4=lig[150:186] dlign5=lig[186:216] dlign6=lig[216:248] l1="" l2="" l3="" cp="" ville="" nom_prenom=lig[56:116].split("/") nom=nom_prenom[0].strip().replace("'", "''") prenom=len(nom_prenom) >=2\ and nom_prenom[1].strip().replace("'", "''")\ or "" nomusage=lig[289:319].strip().replace("'", "''") prenomusage=lig[319:334].strip().replace("'", "''") civilite=lig[286:289].strip() majic3=lig[18:24].strip() # Analyse des infos naissance=isDate(naissance)\ and ("cast('%s 00:00:00' AS DATETIME)" % naissance)\ or "NULL" frmjur="'%s'" % (frmjur == " " and "P" or frmjur) if expnee == "EXP": dnomcp=lig[405:435].strip().replace("'", "''") dprncp=lig[435:450].strip().replace("'", "''") else: dnomcp="NULL" dprncp="NULL" # if if pays == " ": pays="F" if gtyp[1:3] == "88": if gtyp[0] == "2": l1=dlign3.strip().replace("'", "''") l2=dlign4.strip().replace("'", "''") l3=dlign5.strip().replace("'", "''") else: if gtyp3 == "2": l1=dlign3.strip().replace("'", "''") l2=dlign4.strip().replace("'", "''") l3=dlign5.strip().replace("'", "''") else: l1=dlign4.strip().replace("'", "''") l2=dlign5.strip().replace("'", "''") # if # if cp=dlign6[0:5] ville=dlign6[6:32].strip().replace("'", "''") l1=l1 != "" and ("'%s'" % l1) or "NULL" l2=l2 != "" and ("'%s'" % l2) or "NULL" l3=l3 != "" and ("'%s'" % l3) or "NULL" cp=cp != "" and ("'%s'" % cp) or "NULL" ville=ville != "" and ("'%s'" % ville) or "NULL" print "INSERT INTO [TESTCad_NORM09].[dbo].[Personnes] ([Majic3_Code], [Civilite_Code],[Nom],[Prenom],[Nom_Usage],[Prenom_Usage],[Representant],[AdresseL1],[AdresseL2],[AdresseL3],[CodePostal],[Commune_Nom],[Pays_Code],[Adresse_Exacte],[DateNaissance],[NomEpx] ,[PrenomEpx] ,[FrmJur_Code] ,[CRPF_ID] ,[DateCreation] ,[DateModification] ,[AuteurCreation] ,[AuteurModification] ,[tmpClePropri]) VALUES ('%s%s','%s','%s','%s','%s','%s',NULL,%s,%s,%s,%s,%s,'%s',1,%s,%s,%s,%s,%s,CURRENT_TIMESTAMP,NULL,'RL',NULL,NULL);" % ( dept, majic3, civilite, nom, prenom, nomusage, prenomusage, l1, l2, l3, cp, ville, pays, naissance, dnomcp, dprncp, frmjur, dept, ) majic2=lig[0:12].strip() indivision=lig[25:26].strip() indivision=indivision != "" and ("'%s'" % indivision) or "NULL" droit=lig[24:25].strip() droit=droit != "" and ("'%s'" % droit) or "NULL" destimpot=lig[26:27].strip() destimpot=destimpot != "" and ("'%s'" % destimpot) or "NULL" print "INSERT INTO [TESTCad_NORM09].[dbo].[Majic] ([Majic2],[Majic3],[Droit_Code],[Indivision_Code],[Destimpot]) VALUES ('%s','%s%s',%s,%s,%s);" % ( majic2, dept, majic3, droit, indivision, destimpot, ) # for # Fermeture fichier fp.close()
Cela vient surement de la première ligne du fichier "140 CALVADOS D416042009"Citation:
tiolebucheron@debianSite:~/test$ python Personnes.py
Traceback (most recent call last):
File "Personnes.py", line 50, in <module>
gtyp3=lig[116]
IndexError: string index out of range
Certaines lignes sont particulières.
Pour stocker cette information j'ai lancé : pyhton Personnes.py > Personnes.sql. Est-il possible de faire afficher à l'écran les lignes causant des erreurs et de passer ces erreurs pour continuer le traitement?
Pour la date de naissance j'ai un autre test à ajouter.
02/02/1979 devient ("cast('02/02/1979 00:00:00' AS DATETIME)" % naissance)
00/00/0000 devient NULL
00/00/0335 devient NULL
00/00/1979 devient ("cast('01/01/1979 00:00:00' AS DATETIME)" % naissance)
Par défaut si l'année est supérieur à 1900 je dois mettre le jour et mois au 01 janvier et conserver l'année.
Merci de votre je continue a effectuer les tests.
Je continue ce post pour vous donner des temps d'exécution. Les problèmes ci dessus sont toujours d'actualité. Je n'ai pas réussit à les résoudre.
J'ai fait le CODE concernant les parcelles. Cela focntionne très bien.
real 2m54.798s
user 0m30.214s
sys 0m18.869s
Contre plus de 30 heures en bash. Merci du gros coup de pouce.
Cette instruction stocke le 117° caractère de la ligne dans "gtyp3". Si la ligne n'a pas 117 caractères, l'instruction renvoie une exception
2 façons de gérer
1) vérfier la taille de la ligne
Code:
1
2
3
4
5 if len(ligne) >= 117: gtyp3=lig[116] else: gtyp3=<autre chose> # fi
2) intercepter l'exception
Code:
1
2
3
4
5 try: gtyp3=lig[116] except IndexError: gtyp3=<autre chose> # try
Alors faut les checker avant
Oui. Tu peux faire un check de ta ligne au début de la boucle et si la ligne ne correspond pas, passer
Code:
1
2
3
4
5
6
7
8
9
10
11
12 def check(ligne) # Ici tout le code de la fonction de check qui, en final, renvoie True or False suivant que la ligne est ok ou pas # check() ... for lig in fp: if check(lig) != True: print "erreur %s" % lig continue # if ... #for
Bref maintenant tu entres dans la problématique générale de l'algo...
Pas de pb. Faut juste modifier la fonction qui checke la date pour lui faire renvoyer une string contenant la date si date correcte ou valeur None si date incorrecte (au lieu d'un simple True/False comme précédemment)
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 # Fonction de vérification de date def checkDate( dateTxt): # Extraction jj/mm/aaaa jj=int(dateTxt[0:2]) mm=int(dateTxt[3:5]) aa=int(dateTxt[6:10]) # Création d'une date avec aa, mm et jj try: # Si la date est incorrecte, il y aura une levée d'exception datetime.date(aa, mm, jj) # Si exception except ValueError: # Cas particulier de l'année if aa >= 1900: # Renvoi date rectifiée return "01/01/%s" % aa else: # La date entrée n'est pas valide return None # if # Ce bloc if/else peut se simplifier en return aa >= 1900 and ("01/01/%s" % aa) or None # try # La date entrée est valide - On la renvoie telle quelle return dateTxt # checkDate() ... # Et ici on récupère la valeur renvoyée qui sera soit la bonne date, soit "None" datenaissance=checkDate(naissance) datenaissance=datenaissance != None\ and ("cast('%s 00:00:00' AS DATETIME)" % datenaissance)\ or "NULL" # Comme tu le vois, on peut compléter une variable avec elle-même
Un problème de résolut. Pour la première ligne du fichier j'ai fait un simple compteur et saute la ligne 1.
Pour la date il ne me lève pas l'erreur je ne comprend pas.
Il me reste encore un petit problème.
Mon fichier
01 TA
02 TA
03 DH
04 TA
Il faut que je récupère
TA
DH
Sans doublons. Je ne vois trop comment faire. Garder en mémoire les types (TA et DH) dans une variable temp dejà saisi et faire une boucle en "splitant"
Avez vous des idées? Suis-je assez clair!!
Merci de votre aide
Tio
Code:cut -d' ' -f2 FICHIER | sort -u
Bonjour
J'ai réussit à résoudre le problème lié à la récupération du TA HP sans doublon
J'ai encore le soucis de la date qui ne lève pas d'erreur.Code:
1
2
3
4
5
6 elif code_enreg == "30" : exo=lig[38:40] if (exo in exo_temp) == False: print "INSERT INTO [TESTCad_NORM09].[dbo].[Parcelles_Exonerees]([Parcelle_ID],[Exoneration_Code]) VALUES ((select MAX(Parcelles.Parcelle_ID) from Parcelles),'%s');" % (exo) exo_temp="%s;%s" % (exo_temp,exo)
Merci de votre suivi
Edit correction code
J'ai résolut le problème pour la date. La fonction marche très bien. Il y avait d'autre cas à prendre en compte.
Normalement tout est prêt pour lancer le traitement.
Cordialement
Re bonjour
Je vais abuser: Pour l'insertion dans la base de données j'ai deux script en perl.
Une question tout d'abord Qui est plus efficace PERL ou PYTHON?
Code:
1
2
3
4
5 #!/usr/bin/perl use strict; use warnings; my $filename = 'Personnes.sql'; system("sort ${filename} --unique --output=${filename}") == 0 or die("echec du sort");
Peux-t-on faire mieux??Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #!/usr/bin/perl use DBI; my $table="Personnes"; my $dbh = DBI->connect("DBI:Sybase:server=XXX", 'xxx', 'xxx', {PrintError => 1}); die "Unable for connect to server $DBI::errstr" unless $dbh; $dbh->do("use TESTCad_NORM09") or die 'Pas de changement de base'; $dbh->do('SET DATEFORMAT DMY'); open(FILE, $table.".sql") or die ("Fichier incorrect"); my $i=0; while(<FILE>) { $i++; $req .= $_; if (($i % 100)==0) { $dbh->do($req) or warn $req; $req=""; } } close FILE; $dbh->do($req) or warn $req;
Merci pour votre suivi et vos conseils.
Cordialement
Tio
Je pense que t'as compris le principe: une fonction pour gérer chaque problème et tu programmes dans ladite fonction tous les cas possibles à prendre en compte
Content que tu aies pu résoudre ton problème de doublon. T'as effectivement trouvé le "if machin in truc". Toutefois, tu peux utiliser un tableau au lieu d'une string
Code:
1
2
3
4
5
6
7
8
9 tab=[] for info in ("a", "a", "a", "b", "c", "c", "c", "d", "e", "e"): if info not in tab: print "info %s" % info tab.append(info) # if # for print "tab=", tab
Certains extrémistes de font une guerre idiote et inutile entre PERL et Python. Ces deux langages sont quasiment équivalents. PERL est toutefois apparu avant Python. A une époque (dans les années 2000), on disait que Python serait le successeur de PERL mais je pense que c'est passé de mode et que PERL va continuer son évolution sans problème.
A la limite, PERL ayant été créé spécialement pour le traitement des fichiers est peut-être un poil plus adapté à ton problème que Python. Mais comme je ne connais pas ce langage (quand j'ai voulu apprendre un nouveau langage il y a 2 ans j'ai choisi d'apprendre Python) , je n'ai pu que te donner une solution Python...
Merci pour ton aide.
J'ai finis le traitement sur environ 8 millions de lignes traités environ 20 erreurs a reprendre à la main. Je trouve que je m'en sort plutôt bien. J'ai fais cela avec PERL et cela c'est bien passé.
Pour tout faire (2heure30). Heureux de ce résultat, je vais traiter les mêmes données sur le même formatage (a peu près). Les derniers fichiers date de 2003 je pourrait faire des comparaisons.
J'ai une petites erreur que je ne comprend pas .
tiolebucheron@debianSite:~/2003/14$ python Personnes.py > Personnes.sql
Traceback (most recent call last):
File "Personnes.py", line 172, in <module>
dept,
IOError: [Errno 28] No space left on device
tiolebucheron@debianSite:~/2003/14$
Merci de votre aide et du suiviCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179 #!/usr/bin/env python # coding: UTF-8 -*- import sys # Gestion système import datetime # Gestion des dates # Fonction de vérification de date # Fonction de vérification de date def checkDate( dateTxt): # Extraction jj/mm/aaaa jj=int(dateTxt[0:2]) mm=int(dateTxt[3:5]) aa=int(dateTxt[6:10]) if aa < 1900: return "FALSE" else: # Création d'une date avec aa, mm et jj try: # Si la date est incorrecte, il y aura une levée d'exception datetime.date(aa, mm, jj) # Si exception except ValueError: # Cas particulier de l'année if aa >= 1900: # Renvoi date rectifiée return "01/01/%s" % aa else: # La date entrée n'est pas valide return "FALSE" # if # Ce bloc if/else peut se simplifier en return aa >= 1900 and ("01/01/%s" % aa) or None # try # La date entrée est valide - On la renvoie telle quelle return dateTxt # checkDate() # Ouverture fichier try: fp=open("PROP.140.NO679", "r") except IOError: print "Impossible d'ouvrir PROP.140.NO679 - Abandon" sys.exit(1) # try i=0 # Traitement fichier PROP.140.NO679 for lig in fp: i=i+1 if i != 1: # Suppression '\n' de fin de ligne if lig[-1] == "\n": lig=lig[0:-1] # Extraction des infos dept=lig[0:2] frmjur=lig[37] naissance=lig[334:344] expnee=lig[402:405] pays=lig[248:251] gtyp3=lig[116] gtyp=lig[116:120] dlign3=lig[120:150] dlign4=lig[150:186] dlign5=lig[186:216] dlign6=lig[216:248] l1="" l2="" l3="" cp="" ville="" nom_prenom=lig[56:116].split("/") nom=nom_prenom[0].strip().replace("'", "''") prenom=len(nom_prenom) >=2\ and nom_prenom[1].strip().replace("'", "''")\ or "" nomusage=lig[289:319].strip().replace("'", "''") prenomusage=lig[319:334].strip().replace("'", "''") civilite=lig[286:289].strip() majic3="NULL" # Analyse des infos if naissance != " ": datenaissance=checkDate(naissance) naissance=datenaissance != "FALSE"\ and ("cast('%s 00:00:00' AS DATETIME)" % datenaissance)\ or "NULL" else: naissance="NULL" frmjur="'%s'" % (frmjur == " " and "P" or frmjur) if expnee == "EXP": dnomcp=lig[405:435].strip().replace("'", "''") dprncp=lig[435:450].strip().replace("'", "''") else: dnomcp="NULL" dprncp="NULL" # if if pays == " ": pays="F" if gtyp[1:3] == "88": if gtyp[0] == "2": l1=dlign3.strip().replace("'", "''") l2=dlign4.strip().replace("'", "''") l3=dlign5.strip().replace("'", "''") else: if gtyp3 == "2": l1=dlign3.strip().replace("'", "''") l2=dlign4.strip().replace("'", "''") l3=dlign5.strip().replace("'", "''") else: l1=dlign4.strip().replace("'", "''") l2=dlign5.strip().replace("'", "''") # if # if cp=dlign6[0:5] ville=dlign6[6:32].strip().replace("'", "''") nom=nom != "" and ("%s" % nom) or "NULL" prenom=prenom != "" and ("%s" % prenom) or "NULL" nomusage=nomusage != "" and ("%s" % nomusage) or "NULL" prenomusage=prenomusage != "" and ("%s" % prenomusage) or "NULL" l1=l1 != "" and ("'%s'" % l1) or "NULL" l2=l2 != "" and ("'%s'" % l2) or "NULL" l3=l3 != "" and ("'%s'" % l3) or "NULL" cp=cp != "" and ("'%s'" % cp) or "NULL" ville=ville != "" and ("'%s'" % ville) or "NULL" majic2=lig[0:12].strip() indivision=lig[25:26].strip() indivision=indivision != "" and ("'%s'" % indivision) or "NULL" droit=lig[24:25].strip() droit=droit != "" and ("'%s'" % droit) or "NULL" destimpot=lig[26:27].strip() destimpot=destimpot != "" and ("'%s'" % destimpot) or "NULL" print "INSERT INTO [TESTCad_NORM09].[dbo].[Majicbis] ([Majic2],[Majic3],[Droit_Code],[Indivision_Code],[Destimpot],[Majic3_Code], [Civilite_Code],[Nom],[Prenom],[Nom_Usage],[Prenom_Usage],[Representant],[AdresseL1],[AdresseL2],[AdresseL3],[CodePostal],[Commune_Nom],[Pays_Code],[Adresse_Exacte],[DateNaissance],[NomEpx] ,[PrenomEpx] ,[FrmJur_Code] ,[CRPF_ID] ,[DateCreation] ,[DateModification],[AuteurCreation] ,[AuteurModification] ,[tmpClePropri]) VALUES ('%s','%s%s',%s,%s,%s,'%s%s','%s','%s','%s','%s','%s',NULL,%s,%s,%s,%s,%s,'%s',1,%s,%s,%s,%s,%s,CURRENT_TIMESTAMP,NULL,'RL',NULL,NULL);" % ( majic2, dept, majic3, droit, indivision, destimpot, dept, majic3, civilite, nom, prenom, nomusage, prenomusage, l1, l2, l3, cp, ville, pays, naissance, dnomcp, dprncp, frmjur, dept, ) # for # Fermeture fichier fp.close()
Tio
J'ai une petite idée sur le problème ESPACE DISQUE INSUFFISANT. Cela pourrait-t-il venir de là?
A+
C'est ok. Merci pour le dépannage et la découverte de python. Mes traitements sont terminés. 15 millions d'enregistrement dans sql. 1/2 pour l'extraction des données et 1/2 journée pour l'insertion dans les base de données.
Merci
Bonjour
Mer revoila.
J'ai une petite question. Je traite un fichier csv pour le mettre sous sql. J'ai réutiliser le script precédent mais en fin de chaine de caractère j'ai un ^M.
Comment je peux le supprimer avec python
y=ligne[10].replace('^M', '')
cela ne fonctionne pas.
Merci de votre aide Tio
Re,
J'ai fait un y=y[0:len(y)-1] il y a surement mieux
Si ligne représente une ligne, alors c'est ligne qu'il faut remplacer et pas ligne[10] qui n'est que son 11° caractère
y=ligne.replace("^M", ""). Mais peut-être ce que toi t'interprètes comme un "^M" est en fait une fin de ligne à la mode zindow. Dans ce cas, tu peux tenter aussi y=ligne.replace("\n", "")
Bon, tu commences à grenouiller en Python mais te manque l'habitude. y=y[0:-1] ou (moins lisible) y=y[:-1]