web-dev-qa-db-fra.com

getopt, getopts ou analyse manuelle - Que utiliser lorsque je veux supporter des options courtes et longues?

Actuellement, j'écris un script Bash qui a les exigences suivantes:

  • il devrait fonctionner sur une grande variété de plates-formes UNIX/Linux
  • il devrait supporter des options de longue à court et (GNU)

Je sais que getopts serait la voie préférée en termes de portabilité, mais afaik, cela ne prend pas en charge les options longues.

getopt prend en charge les options longues mais le BashGuide recommande fortement contre celui-ci:

N'utilisez jamais getOPT (1). GetOpt ne peut pas gérer les cordes d'arguments vides, ni des arguments avec des espaces blancheurs intégrés. S'il vous plaît oublier que cela existait jamais.

Ainsi, il y a toujours la possibilité d'analyser manuelle. C'est une erreur d'erreur, produit un code de chaudron tout à fait, et je dois gérer des erreurs par moi-même (je suppose getopt(s) Faites la manipulation d'erreurs par elles-mêmes).

Alors, quel serait le choix préféré dans ce cas?

36
helpermethod

S'il doit être portable à une gamme de non-unes, vous devez vous en tenir à POSIX SH. Et Afaiu, vous n'avez tout simplement aucun choix que de la manipulation de l'argumentation.

9
vonbrand

getopt vs getopts semble être un problème religieux. En ce qui concerne les arguments contre getopt dans la FAQ Bash :

  • "getopt _ ne peut pas gérer les cordes d'arguments vides" semble se référer à un problème connu avec en option arguments, qu'il ressemble à getopts ne supporte pas du tout (du moins de la lecture help getopts pour bash 4.2.24). De man getopt:

    getOpt (3) Pa analyse de longues options avec des arguments facultatifs donnés à un argument optionnel vide (mais ne peut pas le faire pour des options courtes). Cette getOPT (1) traite des arguments facultatifs qui sont vides comme s'ils n'étaient pas présents.

Je ne sais pas où le "getopt ne peut pas gérer les arguments [...] avec espaces embarqués" vient de, mais testons-le:

  • test.sh:

    #!/usr/bin/env bash
    set -o errexit -o noclobber -o nounset -o pipefail
    params="$(getopt -o ab:c -l alpha,bravo:,charlie --name "$0" -- "$@")"
    eval set -- "$params"
    
    while true
    do
        case "$1" in
            -a|--alpha)
                echo alpha
                shift
                ;;
            -b|--bravo)
                echo "bravo=$2"
                shift 2
                ;;
            -c|--charlie)
                echo charlie
                shift
                ;;
            --)
                shift
                break
                ;;
            *)
                echo "Not implemented: $1" >&2
                exit 1
                ;;
        esac
    done
    
  • cours:

    $ ./test.sh -
    $ ./test.sh -acb '   whitespace   FTW   '
    alpha
    charlie
    bravo=   whitespace   FTW   
    $ ./test.sh -ab '' -c
    alpha
    bravo=
    charlie
    $ ./test.sh --alpha --bravo '   whitespace   FTW   ' --charlie
    alpha
    bravo=   whitespace   FTW   
    charlie
    

On dirait un chèque et un compagnon pour moi, mais je suis sûr que quelqu'un montrera comment j'ai complètement mal compris la phrase. Bien sûr, le problème de la portabilité est toujours debout; Vous devrez décider combien de temps vaut la peine d'être investi dans des plates-formes avec une BASH plus âgée ou non disponible. Mon propre conseil consiste à utiliser le [~ # ~ # ~] [~ # ~ # ~] et BISOUS Lignes directrices - seulement développer pour ceux-ci Les plates-formes spécifiques que vous connaissez vont être utilisées. La portabilité du code Shell passe généralement à 100% à mesure que le temps de développement passe à l'infini.

26
l0b0

Chaque discussion sur cette question met en évidence la possibilité d'écrire le code analysé manuellement - alors que vous pouvez être sûr de la fonctionnalité et de la portabilité. Je vous conseille de ne pas écrire du code que vous pouvez avoir généré et ré-généré par des générateurs de code open-source faciles à utiliser. Utilisez argbash , qui a été conçu pour fournir la réponse définitive à votre problème. C'est un bien documenté Générateur de code disponible en tant que application de ligne de commande , Online ou comme Docker image .

Je conseille contre les bibliothèques de bash, certains d'entre eux utilisent getopt (qui rend tout à fait inutile) et c'est une douleur à regrouper une gigantesque blob de shell illisible avec votre script.

2
bubla

Vous pouvez utiliser getopt sur des systèmes qui le supportent et utilisent une chute pour les systèmes qui ne le font pas.

Par exemple pure-getopt est implémenté dans Pure Bash pour être un remplacement de dépose pour GNU getopt.

0
Potherca