IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Linux Discussion :

BASH Amélioration script


Sujet :

Linux

  1. #1
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut BASH Amélioration script
    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

  2. #2
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 651
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 651
    Par défaut
    Bonjour Tio,

    Citation Envoyé par Tiolebucheron
    Je cherche des idées pour améliorer (rapidité d'exécution) mon script bash
    Tu peux ne pas utiliser :
    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 ?
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    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

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Tiolebucheron Voir le message
    Oui en effet il y a matière a améliorer. Mes cours de shel remonte à 10 ans maintenant, un peu rouillé le gars.
    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

    Citation Envoyé par Tiolebucheron Voir le message
    par contre j'ai par trop compris l'histoire du for!!!
    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
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    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)

  6. #6
    Membre expérimenté Avatar de fransoo
    Inscrit en
    Novembre 2009
    Messages
    209
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 209
    Par défaut
    Citation Envoyé par Tiolebucheron Voir le message
    Re,
    majic3=$(echo "${line:18:6}" | sed -e 's/[[:blank:]]*$//')
    Si la variable ne contient pas d'espaces, peut-être
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    majic3=${line:18:6}; majic3=${majic3%% *}

  7. #7
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    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

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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")
    Merci de votre aide

  8. #8
    Membre expérimenté Avatar de fransoo
    Inscrit en
    Novembre 2009
    Messages
    209
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 209
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      cpt=$(echo "($cpt + $un)" | bc)
      if [ "$(echo "($cpt % $cent)" | bc)" = 0 ]
        then
        END=$(date +%s)
        tps_execution
      fi
    Peut être remplacé par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ((cpt+=$un))
    ((cpt%$cent)) || { END=$(date +%s); tps_execution; }
    Apparemment, le script fait beaucoup de mise en forme ; je pense que la comande printf pourrait faire une bonne part du boulot.

  9. #9
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    		#dnomcp=$(echo "${line:405:30}" | sed -e 's/[[:blank:]]*$//' | sed -e "s/'/''/g")
    Pour le mettre avec un seul sed.

    Merc à tous de votre aide.

  10. #10
    Membre expérimenté Avatar de fransoo
    Inscrit en
    Novembre 2009
    Messages
    209
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 209
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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")

  11. #11
    Membre expérimenté Avatar de fransoo
    Inscrit en
    Novembre 2009
    Messages
    209
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 209
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    nom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $1}' | sed -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 : Sélectionner tout - Visualiser dans une fenêtre à part
    nom=${line:56:60}; nom=${nom%/*}
    puis :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    prenom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $2}')
    # devient
    prenom="${line:56:60}"; prenom=${nom#*/}
    Sinon, quel est le but de Ce serait intéressant à contourner

  12. #12
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    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

  13. #13
    Membre expérimenté Avatar de fransoo
    Inscrit en
    Novembre 2009
    Messages
    209
    Détails du profil
    Informations forums :
    Inscription : Novembre 2009
    Messages : 209
    Par défaut
    Ça pourrait être intéressant de poster quelques lignes du fichier source et le résultat escompté.

  14. #14
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    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
    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);
    C'est assez trivial, l'objet est de saisir une base de données; Mon script pour le lancement sql est déjà optimisé.

  15. #15
    Modérateur
    Avatar de N_BaH
    Profil pro
    Inscrit en
    Février 2008
    Messages
    7 651
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2008
    Messages : 7 651
    Par défaut
    Citation Envoyé par Tiolebucheron
    par contre j'ai par trop compris l'histoire du for!!!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for var in l2 l3 pc ville; do [ -z ${!var} ] && eval $var="NULL"; done
    Ça fait le même chose, mais tient sur une ligne.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  16. #16
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Tiolebucheron Voir le message
    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
    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
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    nom=$(echo "${line:56:60}" | awk 'BEGIN{FS="/"} {print $1}')
    Par
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    nom=$(echo "${line:56:60}" | cut -d/ -f1)

    Moins important mais à ne pas négliger: on peut aussi remplacer
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    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 bash : Sélectionner tout - Visualiser dans une fenêtre à part
    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"
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    if [ -z "$naissance" -o "$naissance" = "          " -o "$naissance" = "00/00/0000" ]
    => un seul appel à test au lieu de 3

    Et (je l'ai raté mais j'aurais dû le dire hier) on peut remplacer chaque test simple, comme celui-ci
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if [ -z "$ville" ]
        then
          ville="NULL"
      else
          ville="'$ville'"
      fi

    Par un test encore plus simple
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    [ -z "$ville" ] && ville="NULL" || ville="'$ville'"

    Et ptet essayer de gagner en lisibilité en le mettant dans le sens logique
    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    [ -n "$ville" ] && ville="'$ville'" || ville="NULL"
    Car il semble naturel d'espérer plus de présences que d'abscences.

    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...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  17. #17
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    792
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 792
    Par défaut
    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.

  18. #18
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    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

  19. #19
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Tiolebucheron Voir le message
    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
    Si j'ai le temps cet aprem je te porterai ton script et tu verras la simplicité

    Citation Envoyé par Tiolebucheron Voir le message
    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?
    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 bash : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    }
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  20. #20
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    151
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 151
    Par défaut
    Je te remet la version actuelle des deux scripts.

    Merci pour ton aide. j'ai lancé le script 1 38h3 d'exécution.

    Code 1

    Code 2
    Merci d'avoir déjà pris du temps pour me répondre.

    Cordialement

Discussions similaires

  1. Besoin d'aide pour script bash : amélioration
    Par stabo dans le forum Shell et commandes GNU
    Réponses: 11
    Dernier message: 25/05/2012, 13h31
  2. Export de variable d'un script bash à un script perl
    Par neg12 dans le forum Programmation et administration système
    Réponses: 4
    Dernier message: 09/03/2011, 20h45
  3. [débutant] [BASH] problème script backup
    Par julien.63 dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 13/04/2008, 18h56
  4. Problème de script Bash dans script Perl
    Par Aviator dans le forum Langage
    Réponses: 3
    Dernier message: 03/01/2008, 20h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo