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 :

Comment supprimer un argument d'une liste ?


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 Comment supprimer un argument d'une liste ?
    Bonjour,

    Avant de me lancer dans tout un tas de tests, je voudrais savoir si quelqu'un a déjà été confronté au problème suivant et connait déjà une réponse simple à la question posée (sinon je chercherai par moi-même!).

    J'utilise ksh, avec le mode nounset positionné.

    J'ai une super-fonction "superFoo" qui reçoit un certain nombre (variable et éventuellement nul) de paramètres. Elle teste parmi ceux-ci la présence d'un indicateur "skiperror" (dont la présence va avoir certaines conséquences (par exemple, le positionnement d'une variable)), puis elle appelle une sous-fonction "subFoo" en lui passant les paramètres qu'elle a reçus. Donc, en gros, quelque chose comme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function superFoo {
      # Pour simplifier, on suppose qu'il n'y a pas d'argument pouvant "contenir" skiperror
      # sans être exactement "skiperror"
      if print ${1+"$@"} | fgrep -q skiperror ; then
        SKIPERROR=true
      else
        SKIPERROR=false
      fi
      subFoo ${1+"$@"}
      typeset -i res=$?
      if [[ $SKIPERROR = true ]] ; then
        : # etc.
      fi
    }
    Je voudrais savoir s'il existe une manière simple de supprimer "skiperror" de ${1+"$@"} dans la partie "then", afin de ne PAS le passer à "subFoo".

    La difficulté est de gérer des arguments pouvant contenir des espaces, comme:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    superFoo "a b" skiperror "c d"
    qui devrait, in fine, appeler:
    Une autre (petite) difficulté est que, lorsque "nounset" est positionnée (set -u), l'extension de paramètre $@ provoque une erreur parameter not set lorsque la fonction est appelée sans aucun argument. Mais ce cas peut être facilement traité par un test préalable sur $#.

    Merci d'avance aux experts!

    )jack(

  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,

    tu peux nous rappeler à quoi sert ${1+"$@"}
    si tu peux t'en passer, tu pourrais appeler ta fonction ainsi : subfoo "${@//skiperror}"

    quelle version de KSH utilises-tu ?
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  3. #3
    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 N_BaH Voir le message
    Bonjour,
    si tu peux t'en passer, tu pourrais appeler ta fonction ainsi : subfoo "${@//skiperror}"
    Merci N_BaH d'avoir répondu si vite! Mais ça le fait pas (voir plus bas).

    Citation Envoyé par N_BaH Voir le message
    quelle version de KSH utilises-tu ?
    tu peux nous rappeler à quoi sert ${1+"$@"}
    Les scripts qu'on écrit sont censés tourner dans plusieurs environnements , principalement linux RedHat (avec pdksh) et AIX (avec son ksh), mais occasionnellement aussi HP-UX et Solaris... donc j'aimerais une solution aussi portable que possible ( :aie_pas_taper: )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ uname -a
    Linux host1 2.6.18-128.7.1.el5 #1 SMP Wed Aug 19 04:00:49 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
    $ echo $KSH_VERSION
    @(#)PD KSH v5.2.14 99/07/13.2
    $ set -u
    $ echo $@
    ksh: @: parameter not set
    $ echo ${ABC//def} 
    ksh: : bad substitution
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ uname -a
    AIX host2 1 6 00046FCAD400
    $ ^V
    Version M-11/16/88f
    $ set -u
    $ echo $@
    ksh: @: 0403-041 Parameter not set.
    $ echo ${@//def}
    ksh: ${@//def}: 0403-011 The specified substitution is not valid for this command.
    Comme je le disais précédemment, l'extension de $@ provoque une erreur car, lorsque le nombre d'arguments est nul, la variable "@" n'est pas positionnée et le mode nounset n'aime pas ça...

    D'après le bouquin de Korn, lors de l'extension de ${A+B}:
    si A est "unset", ça ne produit rien (même pas une chaîne vide);
    si A est "set", ça produit l'extension de B

    Donc, pour ${1+"$@"}: s'il n'y a pas d'argument, alors 1 est "unset" => ça ne produit rien.
    s'il y a un ou des arguments, alors 1 est "set" => ça produit "$@" qui, du coup, ne plante pas et génère les arguments avec les bons guillemets.

    Par contre, la "solution" avec "//" ne fonctionne pas! (apparemment pas reconnu par les ksh)

    Je pensais faire des essais avec "set --" en testant chaque argument (à suivre...), mais je ne suis pas trop familier...

    )jack(

  4. #4
    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 jack-ft
    Comme je le disais précédemment, l'extension de $@ provoque une erreur car, lorsque le nombre d'arguments est nul, la variable "@" n'est pas positionnée et le mode nounset n'aime pas ça...
    J'aurais plutôt fait un simple test sur le nombre d'arguments (test $# -ge 1).
    Je pensais faire des essais avec "set --" en testant chaque argument
    'p'têt pas besoin du set --, si tu fais une boucle for pour (effectivement je ne vois que ça) tester chaque argument
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    subfoo() { for i do test "$i" = "c d" || echo "$i"; done;}
    subfoo a b "c d" e f
    a
    b
    e
    f
    ...
    ?
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

  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
    Citation Envoyé par N_BaH Voir le message
    J'aurais plutôt fait un simple test sur le nombre d'arguments (test $# -ge 1).
    Oui. C'est que je disais à la fin de mon premier message. L'unique (petit) inconvénient est qu'il peut y avoir un peu de duplication de code dans les 2 branches du "if", mais ce n'est pas bien gênant.

    'p'têt pas besoin du set --, si tu fais une boucle for pour (effectivement je ne vois que ça) tester chaque argument
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    subfoo() { for i do test "$i" = "c d" || echo "$i"; done;}
    subfoo a b "c d" e f
    a
    b
    e
    f
    ...
    ?
    Merci d'avoir essayé!... mais... mouais...

    Euh... je ne voulais pas trop entrer dans les détails, car c'est un peu compliqué... mais ta proposition me montre que ma demande n'est pas assez précise!

    En fait, il existe plusieurs fonctions "superFoo" ("superBar", etc.) construites (plus ou moins) sur le même principe. Chacune reçoit au moins 2 arguments. Le premier est un "receveur" (au sens "objet") et le 2ème un message qui sert à déterminer dynamiquement la fonction "subFoo1" (ou "subFoo2" ou "subBar1", "subBar2", etc.) qui sera appelée avec, comme arguments, le "receveur" et les autres arguments de la superfonction, si possible dépouillés des paramètres genre "skiperror", eux-mêmes traités par la superfonction.

    Voilà. J'espère que c'est plus clair!

    Pour le traitement des 2 premiers arguments, un simple "shift 2" convient, mais, pour le "skiperror" et autres flags, comme ils peuvent apparaître n'importe où dans la liste des arguments suivants, il me faudrait la possibilité de "shifter" le nème argument, lorsque c'est "skiperror", mais pas les précédents!.

    Pour en revenir à ma demande initiale, il s'agit bien d'écrire une fonction "superFoo", de telle manière que l'appel de superFoo x 1 "a b" skiperror "c d" appelle subFoo1 x "a b" "c d".

    En ce qui concerne ta dernière proposition, ce qui ne me convient pas, c'est que je préfère que le "skiperror" soit entièrement géré par la superfonction superFoo et non par toutes les sous-fonctions subFoo1 suFoo2 etc. qui n'ont même pas à en connaître l'existence.

    Si les arguments ne comportaient pas d'espaces, ce serait assez facile, il suffirait de parser les arguments dans la superfonction, de collecter ceux qui ne sont pas des flags (comme skiperror) dans une variable en les séparant par le séparateur d'arguments standard (l'espace) et de passer le tout à la sous-fonction:

    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
    function superFoo {
      typeset receveur=$1 subfun=subFoo$2 ; shift 2
      typeset SKIPERROR=false args="" ifs=" "
      while [[ $# -gt 0 ]] ; do
        case $1 in
          skiperror) SKIPERROR=false ;;
          # autres flags...
          *) args=${args:+${args}${ifs}}$1 ;;
        esac
        shift
      done
      $subfun "$receveur" $args # sans guillemets!!!
      typeset -i res=$?
      if [[ $SKIPERROR = true ]] ; then
        : # etc.
      fi
    }
    De cette manière, l'appel de superFoo x 1 a skiperror b appelle bien subFoo1 x a b.

    Mais, comment faire si les arguments a b (voire x) comportent le séparateur d'arguments (l'espace)???

    Des idées? On peut backslasher les espaces dans les arguments?

  6. #6
    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
    en parsant les arguments, et en les insérant dans un tableau, pour le passer à la "sous-fonction" ?
    N'oubliez pas de consulter les cours shell, la FAQ, et les pages man.

Discussions similaires

  1. [langage] Supprimer un élément dans une liste
    Par myjuna dans le forum Langage
    Réponses: 15
    Dernier message: 06/08/2014, 11h49
  2. Comment supprimer des "0" dans une liste
    Par solorac dans le forum Excel
    Réponses: 4
    Dernier message: 04/09/2007, 12h22
  3. Réponses: 1
    Dernier message: 08/09/2006, 17h21
  4. Réponses: 14
    Dernier message: 15/01/2004, 01h15
  5. [langage] Comment rajouter des champs dans une liste
    Par toto_titi dans le forum Langage
    Réponses: 4
    Dernier message: 28/08/2003, 14h09

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