Comment gérer la fin des options - dans Getopts

9

J'utilise getopts pour analyser les arguments dans les scripts bash comme

while getopts ":hd:" opt; do
  case $opt in
    d ) echo "directory = $OPTARG"; mydir="$OPTARG"; shift $((OPTIND-1)); OPTIND=1 ;;
    h ) helptext
      graceful_exit ;;
    * ) usage
      clean_up
      exit 1
  esac
done

exeparams="$*"

exeparamscontiendra toutes les options / arguments non analysés. Étant donné que je veux utiliser exeparams pour conserver les options d'une commande à exécuter dans le script (qui peut chevaucher les propres options des scripts), je veux utiliser - pour mettre fin aux options transmises au script. Si je passe par exemple

myscript -d myscriptparam -- -d internalparam

exeparams tiendra

-- -d internalparam

Je veux maintenant supprimer le début --pour passer ces arguments à la commande interne. Existe-t-il un moyen élégant de le faire ou puis-je obtenir une chaîne qui contient juste le reste sans --getopts?

highsciguy
la source
Mettre shift; OPTIND=1à l'intérieur de la getoptsboucle n'est probablement pas la meilleure façon de le faire. Cela ne fonctionne que dans votre cas car vous n'avez que 2 options et dans toutes les autres, vous venez de quitter le script. Sinon, vous auriez besoin shift; OPTIND=1de chaque option, ce qui signifie du code en double (mauvaise pratique). Faites juste un shift $((OPTIND - 1))immédiatement après la fin de la boucle - c'est la manière la plus conventionnelle et probablement la plus efficace aussi.
jw013

Réponses:

7

Que diriez-vous:

# ... getopts processing ...

[[ $1 = "--" ]] && shift
exeparams=("$@")

Remarque, vous devez utiliser un tableau pour contenir les paramètres. Cela gérera correctement tous les arguments contenant des espaces. Déréférencer le tableau avec"${exeparams[@]}"

glenn jackman
la source
1
Cela suppose qu'il n'y a pas d'arguments entre la fin des options et --, c'est script foo -- bar-à- dire qu'ils passeraient foo -- barau programme externe. Ma réponse ne fait pas cette hypothèse car elle n'était pas explicitement énoncée dans la question.
jw013
Sauf là où l'OP dit "Je veux maintenant supprimer le premier -"
glenn jackman
C'était pour l'exemple -- -d internalparams. Dans tous les cas, ma réponse est suffisamment générale pour traiter l'un ou l'autre cas.
jw013
14

Utilisez le intégré shift. Tout d'abord, faites la normale getoptspour votre script. Une fois cette boucle terminée,

shift "$((OPTIND - 1))"

déplacera toutes les options déjà traitées.

À partir de là, vous devrez terminer le traitement des arguments sans option, le cas échéant, dans la première partie du script (avant le --). Une fois que vous rencontrez le --, déplacez-le jusqu'à ce qu'il ne reste que la dernière partie (la -d internalparampartie qui vient après --). Une façon de le faire (en utilisant la bashsyntaxe):

while [[ $# -gt 0 ]]; do
    # process next argument
    case $1 in
    foo) # process foo
    ;;
    --) shift; break;; # found '--', discard it and exit loop
    *) # handle unrecognized argument
    ;;
    esac
    # not '--', so discard the argument and continue
    shift
done

Enfin, il ne reste que le deuxième ensemble d'options / arguments que vous pouvez transmettre. Ne pas utiliser $*pour passer les autres paramètres à une autre commande. Utilisez à la "$@"place, ce qui préserve la division du mot d'origine.

external_command "$@"
jw013
la source
Oui merci! Mais comment trouver exactement --?
highsciguy