Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 14/07/2008, à 11:03

Totor

[résolu?] [bash] - getopts

Bonjour,

getopts permet de traiter des options positionnels d'un script. Il s'agit des options spécifiés par le caractère "-" de la ligne de commande.
Mais quid des options/arguments commençant par "--" ? Est-ce [arguments] de getopts qui le permet ? Auquel cas, quel est son formalise ? Quel est le séparateur à utiliser permettant l'identification des différents arguments "--" autorisés (s'il y a un séparateur à mettre) ?

merci

Dernière modification par Totor (Le 15/07/2008, à 11:52)


-- Lucid Lynx --

Hors ligne

#2 Le 15/07/2008, à 10:46

Totor

Re : [résolu?] [bash] - getopts

Après mult recherches sur le net sans succès, je me suis résigné à écrire une petite fonction vérifiant l'existance d'un paramétre en ligne de commande.

Les paramétres pouvant être valorisés. Cela donne donc le formalise suivant :

--<nom>[=<valeur>]

La fonction prend comme 1er argument le nom du paramétre à rechercher puis l'ensemble de la ligne de commande (sauf $0).
Si elle trouve le paramétre, elle valorise les variables globales OPT avec le nom du paramétre et VAL par sa valeur si elle est indiquée.

Il y a un cas "particulier" : si la valeur renseignée est constituée d'au moins un espace.
Je ne pense pas que cela vienne de la fonction mais plutôt de la façon de lui passer les paramétres. En effet, j'ai réalisé un test : avant l'appel à la fonction, j'affiche l'ensemble des paramétres un à un et je les retrouve très bien !


Voici le contenu du fichier utilisé pour tester (qui fait juste un appel à la fonction et affiche le résulat) :

#!/bin/ksh

export OPT=""
export VAL=""

function rechercheOption
{
        option="$1"
        shift

        OPT=""
        VAL=""
        while [[ ! -z "$1" &&  -z "${OPT}" ]]
        do
                OPT="`echo "$1"| sed "/${option}/!d"`"
                if [ ! -z "${OPT}" ]; then
                        VAL="`echo "$1"|sed "s#${option}[=]\{0,1\}##"`"
                        OPT="${option}"
                fi
                shift
        done
}

rechercheOption $@
echo -e "option=${OPT}\tvaleur=${VAL}"

Un exemple de dysfonctionnement (on voit bien que "titi" est considéré comme un paramétre à part entère hmm) :

bash -x ./test --param2 --param1= --param2="toto titi"
+ export OPT=
+ OPT=
+ export VAL=
+ VAL=
+ rechercheOption --param2 --param1= --param2=toto titi
+ option=--param2
+ shift
+ OPT=
+ VAL=
+ [[ ! -z --param1= ]]
+ [[ -z '' ]]
++ echo --param1=
++ sed '/--param2/!d'
+ OPT=
+ '[' '!' -z '' ']'
+ shift
+ [[ ! -z --param2=toto ]]
+ [[ -z '' ]]
++ echo --param2=toto
++ sed '/--param2/!d'
+ OPT=--param2=toto
+ '[' '!' -z --param2=toto ']'
++ echo --param2=toto
++ sed 's#--param2[=]\{0,1\}##'
+ VAL=toto
+ OPT=--param2
+ shift
+ [[ ! -z titi ]]
+ [[ -z --param2 ]]
+ echo -e 'option=--param2\tvaleur=toto'
option=--param2 valeur=toto

Donc, ma question est : comment transmettre les paramétres à la fonction exactement de la même façon qu'ils ont été mis sur la ligne de commande ?

Note : pour afficher les paramétres de la ligne de commande, rajouter ce code :

i=1
while [ $i -le $# ]
do
        echo "param $i=`eval echo \\$${i}`"
        let i=i+1
done

Merci


-- Lucid Lynx --

Hors ligne

#3 Le 15/07/2008, à 11:49

Totor

Re : [résolu?] [bash] - getopts

Bon, j'ai fini par trouvé une solution mais je ne trouve pas ça très propre roll
(Donc si vous avez une meilleure solution, elle est la bienvenue !)

La voici :

#!/bin/ksh

export OPT=""
export VAL=""

function rechercheOption
{
        option="$1"
        shift

        OPT=""
        VAL=""
        while [[ ! -z "$1" &&  -z "${OPT}" ]]
        do
                OPT="`echo "$1"| sed "/${option}/!d"`"
                if [ ! -z "${OPT}" ]; then
                        VAL="`echo "$1"|sed "s#${option}[=]\?##"`"
                        OPT="${option}"
                fi
                shift
        done
}

ligneCmd="rechercheOption "
for valeur;
do
        ligneCmd="${ligneCmd} \"${valeur}\""
done
eval ${ligneCmd}
echo -e "option=${OPT}\tvaleur=${VAL}"

Dernière modification par Totor (Le 15/07/2008, à 12:50)


-- Lucid Lynx --

Hors ligne

#4 Le 15/07/2008, à 13:07

Totor

Re : [résolu?] [bash] - getopts

Correction d'un bug dans la fonction rechercheOption !
Pour le comprendre, le plus simple est d'utiliser l'ancienne version de la fonction avec les paramétres suivant :

--param2 --param1 --param2test --param2="#toto/\ titi#"

Résultat :
OPT prend la valeur --param2 --> ok
VAL prend la valeur test --> ko ! hmm

Mais bon, la correction :

#!/bin/ksh

export OPT=""
export VAL=""

function rechercheOption
{
        option="$1"
        shift

        OPT=""
        VAL=""

        while [[ -n "$1" &&  -z "${OPT}" ]]
        do
                OPT="`echo "$1"| grep -o "^${option}\(=.*\)\?$"`"
                if [ -n "${OPT}" ]; then
                        VAL="`echo "$1"|sed "s/${option}[=]\?//"`"
                        OPT="${option}"
                fi
                shift
        done
}

ligneCmd="rechercheOption "
for valeur;
do
        ligneCmd="${ligneCmd} \"${valeur}\""
done
eval ${ligneCmd}
echo -e "option=${OPT}\tvaleur=${VAL}"

Dernière modification par Totor (Le 15/07/2008, à 13:15)


-- Lucid Lynx --

Hors ligne

#5 Le 22/11/2008, à 23:35

drfazor

Re : [résolu?] [bash] - getopts

il est possible de contourner la fonction getopts pour qu'elle accepte les arguments long, il suffit de fixer - comme option recevable avec argument. En voila un exemple de script:

#!/bin/bash
# Usage du programme
usage="
script [-b|--bash -p|--perl -f|--force -h|--help] fichier\n
\n
Cree un script dans le langage voulu\n
-b ou --bash: Creation d'un script en bash\n
-p ou --perl: Creation d'un script en perl\n
-f ou --force: Force a la réecriture d'un script\n
-h ou --help: dispense cette aide et quitte\n
"
# Definition des variables par defaut
shebang=""
force=0
# Lecture des options
while getopts "bpfh-:" option
do
    if [ $option = "-" ]
    then
        case $OPTARG in
            bash) option="b";;
            perl) option="p";;
            help) option="h";;
            force) option="f";;
        esac
    fi 

    case $option in
        b)shebang="#!/bin/bash";;
        p)shebang="#!/bin/perl";;
        f)force=1;;
        h)echo $usage && exit 0;;
    esac
done
# Place $1 après les options
shift $(($OPTIND-1))
# Création du chemin du fichier
fichier=$HOME/bin/$1
# Test de l'existance du fichier et de la valeur du flag
if [ -e $fichier ] && [ $force -eq 0 ]
then
    echo "le fichier existe" && exit 1;
fi
# Creation et ecriture du fichier
echo $shebang > $fichier && chmod +x $fichier

# fin du script

En esperant que tu puisses en faire ton bonheur

#6 Le 25/11/2008, à 20:21

Totor

Re : [résolu?] [bash] - getopts

Bonsoir,
Intéressant ! Merci pour cette astuce wink


-- Lucid Lynx --

Hors ligne

#7 Le 21/06/2011, à 18:09

Hizoka

Re : [résolu?] [bash] - getopts

je deterre le sujet,

drfazor => avc ta facon de faire que ce passe-t-il si tu fais :

-test "oui - non.txt"

perso j'ai du me faire un systeme proche de getopts qui me permet de prendre en compte mes arguments longs mais mon élément séparateur c'est le -, donc si j'indique un fichier en contenant un ca ne passe plus...


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#8 Le 22/06/2011, à 15:35

FRUiT

Re : [résolu?] [bash] - getopts

Ben ça marche plutôt très bien :

> cat getopts.example
#!/bin/bash
                                                                                          
while getopts "abn:-:" O "$@"; do                                                         
    [ "$O" = "-" ] && case $OPTARG in                                                     
        test) O=t ;;                                                                      
    esac                                                                                  
    case $O in                                                                            
        t) FILE="${!OPTIND}" ; let "OPTIND += 1" ;;                                       
        n) echo "$OPTARG" ;;                                                              
        a) echo bar ;;                                                                    
    esac                                                                                  
done                                                                                      
shift $(($OPTIND-1))                                                                      
                                                                                          
echo "$FILE"                                                                              
                                                                                          
echo "$@"                                                                                 
> ./getopts.example -a --test "oui - non.txt" -n qux                                      
bar
qux
oui - non.txt

> 

Neon Suite by FRUiT (kde4.6) [url]http://[Merci de relire les règles]/yzm7cee[/url]
"Pour la carotte, le lapin est la plus parfaite incarnation du mal" (R. Sheckley)
clean

Hors ligne

#9 Le 22/06/2011, à 17:17

Hizoka

Re : [résolu?] [bash] - getopts

bon bah je vais modifier completement mon fichier pour y inclure ça alors smile

merci FRUiT !

tu peux m'expliquer :

FILE="${!OPTIND}" ; let "OPTIND += 1"

${!varprefixe*},${!varprefixe@}
Établit une correspondance des noms de toutes les variables déjà déclarées commençant par varprefixe.

mais là c'est pas le cas...
et pourquoi ajouter 1 à OPTIND ?

merci


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#10 Le 22/06/2011, à 18:15

FRUiT

Re : [résolu?] [bash] - getopts

En fait c'est pour gérer les options suivantes le cas échéant (dans l'exemple « -n qux »).

Dans l' astuce de drfazor, l'option est « - », MAIS son $OPTARG associé est en fait le mot de l'option longue.

C'est ce qui se produit ici :

    [ "$O" = "-" ] && case $OPTARG in                                                     
        test) O=t ;;                                                                      
    esac                                                                                  

C'est bien OPTARG qui est testé dans le case (et il vaut « test » et pas le nom du fichier, argument réel de l'option longue), donc pour récupérer le nom de fichier qui suit, je ne peux pas me baser sur cette variable (déjà utilisée) comme dans l'exemple de l'option « -n ».

En suivant le raisonnement de getopts, nous avons donc l'option « -- » suivie du OPTARG « test ». Ce qui vient après « test » est le nom du fichier que je souhaite récupérer (l'argument réel de l'option --test). Ce nom ne commançant pas par « - », getopts détermine que les options sont terminées et que le nom du fichier ne fait pas partie des options, ainsi que toutes les options qui pourraient le suivre (ils sont alors considérés comme des paramètres positionnels quelconques à ne pas traiter). Donc non seulement si une option longue a un argument, on ne peut pas compter sur OPTARG pour le récupérer car déjà utilisé pour la ruse, mais cela induit en plus un décalage de 1 dans le traitement des options.

Car en effet, OPTIND évolue au fil du traitement et s'incrémente séquentiellement correspondant  au numéro du paramètre actuellement analysé. C'est donc un simple nombre. Dans notre séquence, arrivé à « "oui - non.txt" », il vaut 3.

Pour ruser, je dis FILE="${!OPTIND}", ce qui est une référence indirecte à la valeur de OPTIND, soit le paramètre positionnel 3, « $3 ». C'est à dire le nom du fichier. En gros bash va lire « FILE="$3" ».

Comme vu précédemment, getopts va alors croire que les options sont terminées, il faut donc incrémenter encore une fois OPTIND pour qu'il continue d'analyser non pas à partir de « "oui - non.txt" », mais à partir de l'option suivante « -n », et puisse donc traiter des options postérieures à une option longue avec argument « --test arg ». C'est pourquoi intervient :

let "OPTIND += 1"

Qu'il faut rajouter, par conséquent, dans le traitement de toute option longue ayant un argument.

Du coup, une option longue est plus souple avec ce système qu'une option courte normale, car elle peut avoir plusieurs arguments ! (il suffit d'incrémenter OPTIND du nombre d'arguments donnés à l'option longue).

J'espère que ça te semble plus clair (pas sur de mon coup là mais bon :s )

Dernière modification par FRUiT (Le 22/06/2011, à 19:19)


Neon Suite by FRUiT (kde4.6) [url]http://[Merci de relire les règles]/yzm7cee[/url]
"Pour la carotte, le lapin est la plus parfaite incarnation du mal" (R. Sheckley)
clean

Hors ligne

#11 Le 22/06/2011, à 18:54

Hizoka

Re : [résolu?] [bash] - getopts

franchement, merci beaucoup !

c'est bien plus clair !

je connaissais le coup du ${!var} en plus, je l'utilise dans certains scripts...

en tout cas, c'est bien dommage de devoir faire tout ça pour que ca soit fonctionnel.

Merci beaucoup à toi !!


KDE Neon 64bits
Tous mes softs (MKVExtractorQt, HizoSelect, HizoProgress, Qtesseract, Keneric, Services menus...) sont sur github

Hors ligne

#12 Le 22/06/2011, à 19:07

FRUiT

Re : [résolu?] [bash] - getopts

De rian avec plaisir ^^


Neon Suite by FRUiT (kde4.6) [url]http://[Merci de relire les règles]/yzm7cee[/url]
"Pour la carotte, le lapin est la plus parfaite incarnation du mal" (R. Sheckley)
clean

Hors ligne