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

Shell et commandes GNU Discussion :

Parallélisation de traitement via une boucle


Sujet :

Shell et commandes GNU

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur de Production
    Inscrit en
    Mai 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de Production
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2009
    Messages : 37
    Points : 35
    Points
    35
    Par défaut Parallélisation de traitement via une boucle
    Bonjour

    J'ai ecrit un script en Ksh sous Linux, qui va lire un fichier contenant plusieurs lignes.
    pour chaque ligne, via une boucle while read, j’exécute plusieurs traitements.

    Actuellement, mon script est asser long et dure quasiment 1h.
    j'ai voulu faire une // manuelle, via génération de script fils pour traiter le fichier par lot de 20 lignes, je suis descendu a 30 min.

    ma // manuelle étant un peu chiante, disons le, je me demande si y'a pas moyen de faire en sorte de rendre la // automatique par le système (pour lancer la lecture de 8 lignes en // par exemple, et que ca continue jusqu'a ce que le fichier soit lu entièrement) ?

    Je m'y connais pas asser dans ce domaine, du coup, pourriez vous m’éclairer ?

    Merci

    PI : mon script de base est asser con, pour exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #definition de variable
    FIC_LEC=toto.lst
    cat $FIC_LEC | while read line
    do
       cmd1 $line
       cmd2 $line
    done

  2. #2
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 276
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 276
    Points : 12 717
    Points
    12 717
    Par défaut
    Bonjour,
    Es-tu obligé d'utiliser ksh ?
    En bash, il existe une commande pratique pour ça, mais cela n'évite pas ta boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    $ help coproc
    coproc: coproc [NOM] commande [redirections]
        Crée un coprocessus nommé NOM.
     
        Exécute la COMMANDE de manière asynchrone, en connectant la sortie et l'entrée standard
        de la commande par un tube aux decripteurs de fichier affectés aux indices 0 et 1
        d'une variable tableau NOM dans le shell en cours d'exécution.
        Le NOM par défaut est « COPROC ».
     
        Code de retour :
        Renvoie le même code de retour que la COMMANDE.
    Cordialement.

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 549
    Points : 19 377
    Points
    19 377
    Par défaut
    ou alors, tu installes, et apprends à utiliser GNU/parallel.
    il est dit que ça fonctionne comme xargs...
    .
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur de Production
    Inscrit en
    Mai 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de Production
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2009
    Messages : 37
    Points : 35
    Points
    35
    Par défaut
    @disedorgue : aurait tu un exemple à me donner avec ce que tu me donnes ? pas sur de comprendre

    @N_Bah : je suis pas admin du serveur sur lequel je bosse, et ne peut du coup pas installer d'outil, sinon ce serait trop simple

  5. #5
    Expert éminent sénior
    Avatar de Escapetiger
    Homme Profil pro
    Administrateur système Unix - Linux
    Inscrit en
    Juillet 2012
    Messages
    1 474
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Administrateur système Unix - Linux

    Informations forums :
    Inscription : Juillet 2012
    Messages : 1 474
    Points : 11 042
    Points
    11 042
    Par défaut
    Bonjour,
    Citation Envoyé par Chico008 Voir le message
    Actuellement, mon script est asser long et dure quasiment 1h.
    j'ai voulu faire une // manuelle, via génération de script fils pour traiter le fichier par lot de 20 lignes, je suis descendu a 30 min.

    ma // manuelle étant un peu chiante, disons le, je me demande si y'a pas moyen de faire en sorte de rendre la // automatique par le système (pour lancer la lecture de 8 lignes en // par exemple, et que ca continue jusqu'a ce que le fichier soit lu entièrement) ?
    (.../...)
    PI : mon script de base est asser con, pour exemple
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #definition de variable
    FIC_LEC=toto.lst
    cat $FIC_LEC | while read line
    do
       cmd1 $line
       cmd2 $line
    done
    On ne voit pas comment le script parallèlise par 20 et/ou par 8 en "manuel".

    Suivant la cohérence des actions de cmd1 et cmd2, il est possible d'utiliser "basiquement" l'exécution en tâche de fond avec le caractère & qui "rends la main" soit cmd2 $line &, applicable à cmd1 selon le traitement.


    L’exécution en arrière-plan permet à un utilisateur de lancer une commande et de récupérer immédiatement la main pour lancer « en parallèle » la commande suivante (parallélisme logique). On utilise le caractère & pour lancer une commande en arrière-plan.
    Source : http://eric-sanchis.developpez.com/l...duction#LI-4-2
    « Developpez.com est un groupe international de bénévoles dont la motivation est l'entraide au sens large » (incl. forums developpez.net)
    Club des professionnels en informatique

  6. #6
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 276
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 276
    Points : 12 717
    Points
    12 717
    Par défaut
    coproc est la même chose que mettre la commande en background (comme expliqué par Escapetiger), avec la particularité de connecter l'entrée et la sortie sur un tube dont les fd sont déclarés dans un tableau.

    Mais comme le dit Escapetiger , on ne comprends pas trop comment tu parallélises tes commandes...

    Après, tu as peut-être déjà atteint la limite du passage de 1 heure à 30 minutes:
    • combien de processeurs as-tu ?
    • Quel est le taux d'occupation cpu de ta commande non // ?
    • Est-ce que tu sollicites l'écriture disque pour chaque commande ?


    Dis-toi, que si ton process normal prend 1 heure en utilisant par exemple 90 % du cpu, et que tu n'as que 2 coeurs, alors en parallélisant à 2 commandes, tu atteindras déjà ton max qui est ici dans ton exemple de 30 minutes.
    Après lorsque l'on a plus de coeur (genre 24), bien souvent, on ne parallélise pas à 24 commandes car on restreint par des latence sur les bus d'entrée sortie.

    Peut-être que ton algo n'est pas optimum et que l'on peut déjà l'améliorer ?
    Mais pour ça, il faudrait que l'on sache ce que celui-ci doit faire et comment tu as pensé ça...
    Cordialement.

  7. #7
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Que donne l'ajout d'une perluette?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #definition de variable
    FIC_LEC=toto.lst
    cat $FIC_LEC | while read line
    do
       cmd1 $line &
       cmd2 $line &
    done
    ou bien, si cmd2 doit absolument être commencée après que cmd1 est terminée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #definition de variable
    FIC_LEC=toto.lst
    cat $FIC_LEC | while read line
    do
       { cmd1 $line ; cmd2 $line ; } &
    done

  8. #8
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 276
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 276
    Points : 12 717
    Points
    12 717
    Par défaut
    Euh, un petit wait après le done peut-être ?
    Cordialement.

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur de Production
    Inscrit en
    Mai 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de Production
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2009
    Messages : 37
    Points : 35
    Points
    35
    Par défaut
    Y'a une incompréhension

    c'est pas les commandes dans la boucle que je souhaite mettre en //
    mais le traitement par bloc de la boucle, cad mettre x itérations de la boucle en //, donc c'est le while read que je souhaite mettre en //

    pour la // manuel, c'est fait via un autre script, que j'avais fait pour tester, ce n'est pas le script que j'ai mis la.

    enfin, mon script utilise entre 1 et 3% de CPU sur 1 seul cœur, sur les 16 de dispo,
    la cmd1 est une lecture d'un fichier, avec toto en paramètre.
    la cmd2 est une commande progiciel avec en paramètre le résultat de la cmd1
    une fois tout ça fait, j’agrège les données en sortie pour écrire 1 ligne dans un fichier de sortie.
    Si vous voulez demain je vous met le script complet (il est sur mon poste au bureau, la c'est we )

  10. #10
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 276
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 276
    Points : 12 717
    Points
    12 717
    Par défaut
    La deuxième proposition de jack-ft semble la bonne, mais attendons d'avoir une vue plus complète du script pour comprendre comment tu agrèges tes résultats.
    Car en l'état, si tu récupère la sortie des commandes dans la boucle, le fait de les mettre en background juste comme ça, tu ne peux garantir l'ordre d'arriver des résultats et tu auras de la perte si tout est redirigé sur le même flux de sortie.
    Cordialement.

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur de Production
    Inscrit en
    Mai 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de Production
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2009
    Messages : 37
    Points : 35
    Points
    35
    Par défaut
    Via script fils, pas de problème, je recupère bien mon resultat comme il faut.

    par contre il semble que quelqu'un a virer mon script du serveur pendant le week-end :'(
    du coup je peut pas vous le mettre ...

    mais sinon oui, la 2nd solution de Jack semble pas mal, je vais tester ca.

    Bon, j'ai pu retrouver mon script

    Du coup le voici
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    #!/bin/ksh
     
    echo "Start : $(date +'%F_%H:%M:%S')"
    echo "DEBUT : Declaration variables"
     
     
    cd /home/auto113/proc
    FNOW=$(date +"%Y-%m-%d %H:%M:00")
    SEARCH=/home/auto113/exploit/search_machine.sh
    FIC_OUT=/home/auto113/lst/appsrv.csv
    rm -f $FIC_OUT
    CONF="./Conf_WHEREAMI ./Conf_HOMOL_WHEREAMI"
     
    echo "Generation des scripts puis lancement"
    cat $CONF | grev -v "#" | while read line
    do
          APP=$(echo $line | cut -d'|' -f1)
          # on cherche si un jil existe
          ls ../jil/$APP.[jJ][iI][lL] > /dev/null 2>&1
          if [ $? -eq 0 ]; then
             $SEARCH ../jil/$APP.[jJ][iI][lL] | grep Machine > ./tmp1.lst
             cat ./tmp1.lst | while read linb
             do
                NCOL=$(echo $linb | awk '{print NF}')
                case $NCOL in
                4)
                  echo $linb | awk '{print $(NF-1)","$NF}' >> ./tmp2.lst
                  ;;
                5)
                  echo $linb | awk '{print $(NF-2)","$(NF-1)","$NF}' >> ./tmp2.lst
                  ;;
             esac
             done
             SRVLST=$(cat ./tmp2.lst | tr \"\n\" \":\" | sed -e "s/:$//")
             echo "$FNOW;$APP;$SRVLST" >> $FIC_OUT
             rm -f ./tmp2.lst
          else
             echo "$FNOW;$APP;Liste indisponible" >> $FIC_OUT
          fi
    done
    echo "FIN $(date +'%F_%H:%M:%S')"
    du coup selon l'idée de Jack il faudrait ajouter un { après le do
    et un } & avant le done c'est bien ca ?

    Faudra que j'ajoute du code pour limiter le nombre de background et les attendre

  12. #12
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par Chico008 Voir le message
    du coup selon l'idée de Jack il faudrait ajouter un { après le do
    et un } & avant le done c'est bien ca ?
    Oui, c'est l'idée... J'ai pas tout lu, ni tout compris...

    Mais ATTENTION!

    Quand on parallèlise, il ne faut pas se marcher sur les pieds!
    Dans ton code, toutes les itérations de la boucle principale utilisent (et partagent) le même fichier ./tmp1.lst et le même fichier ./tmp2.lst
    Forcément, si tu parallèlise, ça va pas bien marcher du tout!
    De manière générale, il faut toujours se méfier avec les fichiers temporaires.
    Souvent on met "$$" dans le nom du fichier pour que 2 occurrences simultanées du même programme ne partagent pas le même fichier.
    Ici, ça ne marcherait pas.
    Il vaudrait mieux utiliser "mktemp" ou, mieux, se passer d'un fichier intermédiaire, si tu ne veux pas le conserver en fin de traitement.
    Ici, il me semble que tu peux avantageusement remplacer:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
             $SEARCH ../jil/$APP.[jJ][iI][lL] | grep Machine > ./tmp1.lst
             cat ./tmp1.lst | while read linb
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
             $SEARCH ../jil/$APP.[jJ][iI][lL] | grep Machine | while read linb
    Pour tmp2.lst, ton script nettoie après la sous-boucle. Comme il n'y a pas de nettoyage avant, si jamais le script est interrompu pour une raison quelconque, alors, au prochain lancement, la première sous-boucle repartira avec un fichier tmp2.lst non vide (BUG!).

    Vu le traitement que tu fais, tu peux envisager de le faire en ram plutôt que dans un fichier intermédiaire.
    Par exemple quelque chose comme (à vérifier):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
             $SEARCH ../jil/$APP.[jJ][iI][lL] | grep Machine | while read linb
             do
                SRVLST=''
                NCOL=$(echo $linb | awk '{print NF}')
                case $NCOL in
                4)
                  SRVLST=${SRVLST:+$SRVLST:}$(echo $linb | awk '{print $(NF-1)","$NF}')
                  ;;
                5)
                  SRVLST=${SRVLST:+$SRVLST:}$(echo $linb | awk '{print $(NF-2)","$(NF-1)","$NF}')
                  ;;
                esac
             done
             echo "$FNOW;$APP;$SRVLST" >> $FIC_OUT
    mais le plus simple (et le plus rapide) serait de faire un seul script awk plutôt que grep Machine | while read linb...

    PS: Pour la lisibilité, j'aime pas les petits "else" (surtout si c'est un cas d'erreur). Je préfère inverser le test et permuter les clauses du "if".

  13. #13
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 276
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 276
    Points : 12 717
    Points
    12 717
    Par défaut
    Comme le dit Jack-ft, tu peux par exemple remplacer avantageusement:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
             cat ./tmp1.lst | while read linb
             do
                NCOL=$(echo $linb | awk '{print NF}')
                case $NCOL in
                4)
                  echo $linb | awk '{print $(NF-1)","$NF}' >> ./tmp2.lst
                  ;;
                5)
                  echo $linb | awk '{print $(NF-2)","$(NF-1)","$NF}' >> ./tmp2.lst
                  ;;
             esac
             done
             SRVLST=$(cat ./tmp2.lst | tr \"\n\" \":\" | sed -e "s/:$//")
    par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SRVLST=$(awk 'NF==4 || NF==5 {NF==5 ? X=$(NF-2)","$(NF-1)","$NF : X=$(NF-1)","$NF ; printf Y X;Y=":"}' ./tmp1.lst)
    Cordialement.

  14. #14
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur de Production
    Inscrit en
    Mai 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de Production
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2009
    Messages : 37
    Points : 35
    Points
    35
    Par défaut
    effectivement le tmp1 c'est du feneant que fait quand je code en vitesse pour pas trop me prendre la tete, mais je vais m'y mettre

    par contre je comprend pas trop ta ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SRVLST=${SRVLST:+$SRVLST:}$(echo $linb | awk '{print $(NF-1)","$NF}')
    ce serait equivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SRVLST=$SRVLST":"$(echo $linb | awk '{print $(NF-1)","$NF}')
    ?


    @disedorgue : je maitrise pas encore asser le awk pour pondre ce genre de code :p
    et vu qu'il devra être maintenu ensuite par des collègues qui ne maitrisent pas du tout le script, je prefère garder mon case, plus lisible et plus simple a comprendre pour des neophytes
    Mais je retient

  15. #15
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    Es-tu obligé d'utiliser ksh ?
    En bash, il existe une commande pratique pour ça, mais cela n'évite pas ta boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ help coproc
    coproc: coproc [NOM] commande [redirections]
        ...
    Hmm, ksh a introduit les co-processes en 1988, dix neuf ans ans avant que bash ne finisse supporter le concept en 2009 (bash 4.0)...
    ɹǝsn *sıɹɐlos*

  16. #16
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 276
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 276
    Points : 12 717
    Points
    12 717
    Par défaut
    Citation Envoyé par jlliagre Voir le message
    Hmm, ksh a introduit les co-processes en 1988, dix neuf ans ans avant que bash ne finisse supporter le concept en 2009 (bash 4.0)...
    [HUMOUR]De 1988 à 2009, il y a 21 ans, ou alors tu voulais dire 1989 et 2008 [/HUMOUR]
    Sinon, le coproc de ksh que tu parles, c'est bien le fameux |& ?
    Si c'est celui-ci, il est tout de même limité à un seul coprocess à la fois, contrairement à celui plus explicite de bash qui permet d'en lancer plusieurs.

    Citation Envoyé par Chico008 Voir le message
    @disedorgue : je maitrise pas encore asser le awk pour pondre ce genre de code :p
    et vu qu'il devra être maintenu ensuite par des collègues qui ne maitrisent pas du tout le script, je prefère garder mon case, plus lisible et plus simple a comprendre pour des neophytes
    Mais je retient
    Je croyais que tu recherchais de la performance, donc un exemple de ton approche et de l'approche awk:
    La partie de ton code testé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ cat scentest.sh
             cat $1 | while read linb
             do
                NCOL=$(echo $linb | awk '{print NF}')
                case $NCOL in
                4)
                  echo $linb | awk '{print $(NF-1)","$NF}' >> ./tmp2.lst
                  ;;
                5)
                  echo $linb | awk '{print $(NF-2)","$(NF-1)","$NF}' >> ./tmp2.lst
                  ;;
             esac
             done
             cat ./tmp2.lst | tr "\n" ":" | sed -e "s/:$//"
    Testons sur un fichier de 1000 lignes ( en bash : for i in {1..500} ; do echo -e "A B C D E\nR T Y U" ; done >SCEN_1000.txt ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $ rm ./tmp2.lst
    $ time bash scentest.sh SCEN_1000.txt >/dev/null
     
    real    0m4.724s
    user    0m0.994s
    sys     0m2.815s
    Testons la ligne awk sur les mêmes 1000 lignes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ time awk 'NF==4 || NF==5 {NF==5 ? X=$(NF-2)","$(NF-1)","$NF : X=$(NF-1)","$NF ; printf Y X;Y=":"}' SCEN_1000.txt >/dev/null
     
    real    0m0.005s
    user    0m0.004s
    sys     0m0.001s
    Et la ligne awk n'est pas difficile à appréhender, ici j'utilise juste le if-else court ( expr ? action vrai : action faux ), sinon en syntaxe plus parlant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    awk 'NF==4 || NF==5 {if(NF==5){X=$(NF-2)","$(NF-1)","$NF}else{X=$(NF-1)","$NF};printf Y X;Y=":"}' file
    Après, il serait intéressant de savoir quelle partie prend du temps et qui te pousse à faire du // ?
    Cordialement.

  17. #17
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Points : 7 882
    Points
    7 882
    Par défaut
    Citation Envoyé par disedorgue Voir le message
    [HUMOUR]De 1988 à 2009, il y a 21 ans, ou alors tu voulais dire 1989 et 2008 [/HUMOUR]
    Ouch, il faudra que je réapprenne à compter ...

    Sinon, le coproc de ksh que tu parles, c'est bien le fameux |& ?
    Oui, les co-processes ont été inventés par ksh avec la syntaxe |& qui me semble plus intuitive que coproc. On crée un pipe bidirectionnel et la commande est mise en arrière plan.

    Si c'est celui-ci, il est tout de même limité à un seul coprocess à la fois, contrairement à celui plus explicite de bash qui permet d'en lancer plusieurs.
    Ça se discute, j'aurais tendance à penser l'inverse. La syntaxe étendue de la commande coproc de bash permet bien de nommer les descripteurs de fichiers à sa convenance, mais la page de manuel de bash précise dans le chapitre BUGS:

    There may be only one active coprocess at a time.

    Voir aussi https://lists.gnu.org/archive/html/b.../msg00053.html

    Côté ksh, il n'est nulle part précisé qu'un seul co-process est supporté et rien n’empêche d'en lancer plusieurs. Il suffit dans ce cas de préserver en les dupliquant les deux descripteurs de fichiers du dernier co-process exécuté avant de lancer le suivant, par exemple comme ça :

    Mais cela dit, pour faire ce que permettent les co-processes, je préfère aujourd'hui plutôt utiliser des pipes nommés ou expect.
    ɹǝsn *sıɹɐlos*

  18. #18
    Expert éminent sénior Avatar de disedorgue
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Décembre 2012
    Messages
    4 276
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Décembre 2012
    Messages : 4 276
    Points : 12 717
    Points
    12 717
    Par défaut
    Super, je comprends mieux pourquoi j'avais des problèmes aléatoires quand j'avais essayé d'utiliser ce coproc de bash avec openssl et que j'ai fini par passer par des pipes nommés (que je préfère aussi et quand c'est possible de les créer dans la share memory).
    Cordialement.

  19. #19
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Développeur informatique en retraite

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 101
    Points : 5 849
    Points
    5 849
    Par défaut
    Citation Envoyé par Chico008 Voir le message
    je comprend pas trop ta ligne SRVLST=${SRVLST:+$SRVLST:}$(echo $linb | awk '{print $(NF-1)","$NF}')...
    ce serait equivalent à SRVLST=$SRVLST":"$(echo $linb | awk '{print $(NF-1)","$NF}') ?
    C'est équivalent uniquement lorsque $SRVLST est non nul et non vide, c'est-à-dire après la première itération de la boucle.

    Ce serait plutôt quasiment équivalent à quelque chose comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if test -z "${SRVLST}"
    then SRVLST=$(echo $linb | awk '{print $(NF-1)","$NF}')
    else SRVLST=${SRVLST}:$(echo $linb | awk '{print $(NF-1)","$NF}')
    fi
    Ça permet d'avoir exactement un ":" entre chaque paire de valeurs.

    Plus précisément, c'est équivalent à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    if test -z "${SRVLST:-}" # Pour éviter les erreurs provoquées par un éventuel "set -u"
    then SRVLST=$(echo $linb | awk '{print $(NF-1)","$NF}')
    else SRVLST=${SRVLST}:$(echo $linb | awk '{print $(NF-1)","$NF}')
    fi
    Pour tester:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    A=''  # ou bien: unset A
    A=${A:+$A:}B
    echo $A
    => B
    A=${A:+$A:}C
    echo $A
    => B:C
    etc.
    Juste par souci de précision, ceci marche aussi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    unset A
    A=${A+$A:}B
    echo $A
    => B
    A=${A+$A:}C
    echo $A
    => B:C
    etc.
    mais pas ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    A=''
    A=${A+$A:}B
    echo $A
    => :B
    A=${A+$A:}C
    echo $A
    => :B:C
    etc.

  20. #20
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur de Production
    Inscrit en
    Mai 2009
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur de Production
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Mai 2009
    Messages : 37
    Points : 35
    Points
    35
    Par défaut
    @Dise : merci pour tes explications
    par contre, peut tu m'expliquer le print final ? (printf Y X;Y=":") je ne le comprend pas. (sauf le X, mais d'ou vient le Y)

    @jack : merci, c'est plus clair, je connaissait pas ces syntaxes

Discussions similaires

  1. [loop] ralentir le traitement d'une boucle
    Par jontleman dans le forum Windows Forms
    Réponses: 7
    Dernier message: 30/11/2007, 14h34
  2. Insertion de champ via une boucle
    Par mat67000 dans le forum Access
    Réponses: 13
    Dernier message: 26/06/2007, 13h53
  3. [DEBUTANT]Procédure stockée Traitement sur une boucle de requete
    Par tripper.dim dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 21/06/2007, 16h24
  4. Auto commit via une boucle
    Par magic charly dans le forum Sql*Plus
    Réponses: 7
    Dernier message: 06/12/2006, 15h01
  5. Réponses: 4
    Dernier message: 26/08/2004, 08h01

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