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 :

Calculer efficacement le nombre de champs d'une string


Sujet :

Shell et commandes GNU

  1. #1
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut Calculer efficacement le nombre de champs d'une string
    Bonjour.

    Petit problème de débutant!

    J'ai une chaîne 'un_champ:un_autre_champ:encore_un' qui contient, sur une seule ligne, des champs séparés par le séparateur ':'.
    Je voudrais calculer le nombre de champs de cette chaîne.

    J'ai bien la solution extrêmement simple avec awk:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typeset LISTE='un_champ:un_autre_champ:encore_un'
    typeset -i nf=$(print "${LISTE}" | awk -F ":" '{print NF}')
    print ${nf}
    3
    mais je la soupçonne d'être passablement coûteuse... surtout pour une petite chaîne!

    ou la solution de suppression des autres caractères avec sed:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    typeset LISTE='un_champ:un_autre_champ:encore_un'
    typeset lif=$(print "${LISTE}" | sed -e 's/[^:]//g')
    typeset -i nf=$((${#lif} + 1))
    print ${nf}
    3
    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typeset LISTE='un_champ:un_autre_champ:encore_un'
    typeset -i nf=$(print "${LISTE}" | sed -e 's/[^:]//g' | wc -c) 
    print ${nf}
    3
    Les spécialistes savent-ils quelle solution (parmi celles-ci ou d'autres, valables pour ksh) est la plus efficace?

  2. #2
    Membre expérimenté
    Avatar de l4r3nZu
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2010
    Messages
    154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2010
    Messages : 154
    Par défaut
    Je n'ai pas tester ma commande mais ca doit etre un truc dansle genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    wc -l $($(echo"tt:tt:tt" | cut -d":"))

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

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

    en bash :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ string="un_champ:un_autre_champ:encore_un"
    $ nf="${string//[^:]/}"
    $ echo $((${#nf}+1))
    3
    il n'y a pas de raisons que ça ne fonctionne pas avec ksh.
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  4. #4
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Merci d'avoir répondu!

    Citation Envoyé par l4r3nZu Voir le message
    Je n'ai pas tester ma commande
    Ah ben, oui, je confirme!

    mais ca doit etre un truc dans le genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    wc -l $($(echo"tt:tt:tt" | cut -d":"))
    En fait, cut sert à extraire des champs, mais ne permet pas de les "séparer" par des returns!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # sous linux:
    echo $string | cut -d":"      
    cut: you must specify a list of bytes, characters, or fields
     
    # sous AIX:
    echo $string | cut -d":"
    Usage: cut -b List [-n] [File...]
       or: cut -c List [File...]
       or: cut -f List [-d Character] [-s] [File...]
    Mais, du coup, ça me fait penser à une autre solution avec 'tr' et 2 pipes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typeset -i nf=$(print "${string}" | tr ':' '\n' | wc -l)
    Rq: le 'typeset -i' permet de supprimer le formatage introduit par wc sous AIX.

  5. #5
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Merci d'avoir répondu.

    Citation Envoyé par N_BaH Voir le message
    Bonjour,

    en bash :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ string="un_champ:un_autre_champ:encore_un"
    $ nf="${string//[^:]/}"
    $ echo $((${#nf}+1))
    3
    il n'y a pas de raisons que ça ne fonctionne pas avec ksh.
    C'est ce qu'on va voir... et c'est tout vu!

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    # Sous AIX
    $ nf="${string//[^:]/}"
    ksh: nf="${string//[^:]/}": 0403-011 The specified substitution is not valid for this command.
     
    # Sous linux
    $ nf="${string//[^:]/}"
    ksh: : bad substitution
    Mais, c'était bien essayé!

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 646
    Par défaut
    il faudrait trouver des noms différents pour des shells qui ont un comportement aussi différent !

    évidemment, avec ksh Version AJM 93u+ 2012-08-01, je n'ai pas de problème avec ces commandes.

    dans la même idée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $ nf=$(echo "$string" | tr -d -c ':')
    $ echo $((${#nf}+1))
    3
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  7. #7
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Citation Envoyé par N_BaH Voir le message
    Bonjour,

    en bash :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ string="un_champ:un_autre_champ:encore_un"
    $ nf="${string//[^:]/}"
    $ echo $((${#nf}+1))
    3
    il n'y a pas de raisons que ça ne fonctionne pas avec ksh.
    Citation Envoyé par N_BaH Voir le message
    il faudrait trouver des noms différents pour des shells qui ont un comportement aussi différent !
    Je confirme l'erreur sous KSH Version M-11/16/88f sous AIX et en KSH Version M-11/16/88i sous Solaris, et en 11/16/88 sous HP-UX...

    Neanmoins, c'est probablement la version la plus rapide que l'on peut obtenir, car il n'y a pas d'indirection (pipe ou autres).
    Reste a faire un portage sous des vieux KSH

    PS : la version avec "echo | tr" fonctionne bien
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  8. #8
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Je confirme l'erreur sous KSH Version M-11/16/88f sous AIX et en KSH Version M-11/16/88i sous Solaris, et en 11/16/88 sous HP-UX...
    Merci pour ces précisions!

    Reste a faire un portage sous des vieux KSH
    Oui, parce que notre projet tout moderne (dans une grande boite connue, avec plein de logiciels utilisés par tout le monde) repose, en grande partie, sur ces belles architectures!

  9. #9
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 134
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 134
    Par défaut
    Souvent, ksh identifie la version 88 du shell Korn mais on peut accéder à la version 93 avec l'exécutable ksh93.
    Vérifie sur ton système...
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  10. #10
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Citation Envoyé par al1_24 Voir le message
    Souvent, ksh identifie la version 88 du shell Korn mais on peut accéder à la version 93 avec l'exécutable ksh93.
    Vérifie sur ton système...
    Chez moi, c'est dispo sur AIX
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  11. #11
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par al1_24 Voir le message
    Souvent, ksh identifie la version 88 du shell Korn mais on peut accéder à la version 93 avec l'exécutable ksh93.
    Vérifie sur ton système...
    Merci pour cette sollicitude!

    Effectivement, j'ai bien vu ce ksh93... mais:
    - je n'ai pas les autorisations pour faire pointer ksh vers ksh93
    - les administrateurs système ne le feront jamais
    - je me vois mal demander aux utilisateurs de changer le shebang de leurs scripts (qui devront, de toute façon, être portables sur toutes les architectures de la maison)

    J'en suis réduit à utiliser le plus petit dénominateur commun des différents 'ksh' (ainsi que des outils unix (df sed grep...)) fournis sur les plateformes officiellement supportées ici...

    D'après mon expérience, en général, quand ça passe sous AIX, c'est bon pour les autres...

  12. #12
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Citation Envoyé par jack-ft Voir le message
    D'après mon expérience, en général, quand ça passe sous AIX, c'est bon pour les autres...
    Se mefier d'HP-UX, il est capable d'avoir quelques specificites bien sympa aussi.
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

  13. #13
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par gangsoleil Voir le message
    Se mefier d'HP-UX, il est capable d'avoir quelques specificites bien sympa aussi.
    Ouais! C'est pas faux!
    (c'est "spécificités" que t'as pas compris?)

    Petite remarque: en remplaçant l'appel de awk par tr, j'ai eu 3 tests en échec (sur 430).
    J'en déduis donc que les 2 formes ne sont pas complètement équivalentes.
    (elles le sont à 99.3%, d'une certaine manière...)

    Si leur interprétation est la même dans de nombreux cas:

    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
    $ echo 'a:b' | awk -F: '{print NF}'
    2
    $ lif=$(echo 'a:b' | tr -d -c ':') ; echo $((${#lif}+1))
    2
    $ echo ':b' | awk -F: '{print NF}'  
    2
    $ lif=$(echo ':b' | tr -d -c ':') ; echo $((${#lif}+1))  
    2
    $ echo ':' | awk -F: '{print NF}'  
    2
    $ lif=$(echo ':' | tr -d -c ':') ; echo $((${#lif}+1))  
    2
    $ echo 'a' | awk -F: '{print NF}' 
    1
    $ lif=$(echo 'a' | tr -d -c ':') ; echo $((${#lif}+1)) 
    1
    En revanche, leur interprétation d'une chaîne vide diffère:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ echo '' | awk -F: '{print NF}'  
    0
    $ lif=$(echo '' | tr -d -c ':') ; echo $((${#lif}+1))
    1
    D'où la question philosophique: combien de champs séparés par ':' la chaîne vide contient-elle?

    On vote?

  14. #14
    Membre Expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Par défaut
    Sous Linux on peut aussi utiliser "grep -Fo :" pour compter les ":"

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

    Informations forums :
    Inscription : Février 2008
    Messages : 7 646
    Par défaut
    qu'est-ce qu'il disait ? il est pas chipoteur ? ...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    for str in '' "a" "a:" "a:b" "a:b:c"
    do
       nf=$(echo "$str" | tr -d -c ':')
       echo $((n=${#nf}, ${#str} || n?n+1:n))
    done
    0
    1
    2
    2
    3
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  16. #16
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par matafan Voir le message
    Sous Linux on peut aussi utiliser "grep -Fo :" pour conter les ":"
    Ah! raconter les ":"...

    Amis conteurs, faites vos comptes!

    euh... sinon, à part ça, évidemment, ça ne marche pas sous AIX.

  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
    Par défaut
    Une syntaxe qui passe avec ksh88:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ LISTE='un_champ:un_autre_champ:encore_un'
    $ NF=$(set $(echo "$LISTE"|tr ':' ' ');echo $#)
    $ echo $NF
    3

  18. #18
    Expert confirmé
    Homme Profil pro
    Développeur informatique en retraite
    Inscrit en
    Avril 2008
    Messages
    2 102
    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 102
    Par défaut
    Citation Envoyé par jlliagre Voir le message
    Une syntaxe qui passe avec ksh88:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ LISTE='un_champ:un_autre_champ:encore_un'
    $ NF=$(set $(echo "$LISTE"|tr ':' ' ');echo $#)
    $ echo $NF
    3
    Exact!

    Restriction #1: les champs ne doivent pas contenir d'espaces
    Restriction #2: les champs ne doivent pas être vides

    D'où la solution:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ LISTE=':apres un champ initial vide:un autre champ:::apres deux champs et avant un dernier vides:'
    $ NF=$(set $(echo "_$LISTE" | sed -e 's/ //g;s/:/ _/g');echo $#)
    $ echo $NF
    7

  19. #19
    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
    Citation Envoyé par jack-ft Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $ LISTE=':apres un champ initial vide:un autre champ:::apres deux champs et avant un dernier vides:'
    $ NF=$(set $(echo "_$LISTE" | sed -e 's/ //g;s/:/ _/g');echo $#)
    $ echo $NF
    7
    Je doute qu'un set --> echo --> sed --> echo soit plus économe que la solution awk ou mieux, un tr -cd : | wc -c comme suggéré plus haut par N_BaH.

    Testé sur une longue chaîne (contenue dans le fichier 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
    jeanluc@ibm:~/scripts/test$ time set $(sed -e 's/ //g;s/:/ _/g' fichier_test); echo $#
    real	0m0.042s
    user	0m0.032s
    sys	0m0.008s
     
    jeanluc@ibm:~/scripts/test$ time awk -F":" '{print NF}' fichier_test 
    real	0m0.007s
    user	0m0.008s
    sys	0m0.000s
     
    jeanluc@ibm:~/scripts/test$ time tr -cd : < fichier_test | wc -c
    real	0m0.004s
    user	0m0.000s
    sys	0m0.004s

  20. #20
    Modérateur
    Avatar de gangsoleil
    Homme Profil pro
    Manager / Cyber Sécurité
    Inscrit en
    Mai 2004
    Messages
    10 150
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Manager / Cyber Sécurité

    Informations forums :
    Inscription : Mai 2004
    Messages : 10 150
    Par défaut
    Citation Envoyé par ripat Voir le message
    Je doute qu'un set --> echo --> sed --> echo soit plus économe que la solution awk ou mieux, un tr -cd : | wc -c comme suggéré plus haut par N_BaH.
    Sans faire les tests, il faut savoir que ce qui coute le plus cher (pour peu que l'on fasse des appels simples), ce sont toujours les indirections. Donc oui, tu as de bonnes raisons de douter (ce que montrent tes tests).
    "La route est longue, mais le chemin est libre" -- https://framasoft.org/
    Les règles du forum

Discussions similaires

  1. Calcul d'un nombre de caractères dans une chaîne
    Par Thekiller dans le forum Langage
    Réponses: 7
    Dernier message: 08/02/2010, 23h21
  2. Compter le nombre de champs d'une table
    Par alexsimps dans le forum SQL Procédural
    Réponses: 1
    Dernier message: 22/07/2007, 08h03
  3. Nombre de champs d'une base
    Par lohot dans le forum Bases de données
    Réponses: 1
    Dernier message: 09/02/2007, 23h11
  4. grand nombre de champ dans une table
    Par drinkmilk dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 21/06/2006, 18h54
  5. Nombre de champs d'une table
    Par cege dans le forum Access
    Réponses: 4
    Dernier message: 25/01/2005, 17h57

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