Je me souviens avoir vu quelque part un bash
script utilisant case
et shift
parcourant la liste des paramètres de position, analysant les drapeaux et les options avec des arguments lorsqu'il les rencontre, et les supprimant après l'analyse pour ne laisser que les arguments nus, qui sont ensuite traités par le reste de la scénario.
Par exemple, en analysant la ligne de commande de cp -R file1 -t /mybackup file2 -f
, il parcourrait d'abord les paramètres, reconnaîtrait que l'utilisateur a demandé de descendre dans les répertoires par -R
, spécifié la cible par -t /mybackup
et pour forcer la copie par -f
, et supprimait ceux de la liste des paramètres, laissant le programme à traiter file1 file2
comme arguments restants.
Mais je ne semble pas être capable de me souvenir / découvrir quel que soit le script que j'ai vu à chaque fois. J'aimerais juste pouvoir faire ça. J'ai fait des recherches sur divers sites et j'ai joint une liste des pages pertinentes que j'ai examinées.
Une question sur ce site Web portait spécifiquement sur les "options indépendantes de l'ordre", mais la réponse unique et la réponse à la question à laquelle elle a été dupliquée ne prennent pas en compte des cas comme celui ci-dessus où les options sont mélangées avec des arguments normaux, ce qui, je présume, était le raison pour laquelle la personne mentionne spécifiquement les options indépendantes de la commande .
Étant donné que bash
la fonction intégrée getopts
semble s'arrêter au premier argument de non-option, elle ne semble pas être une solution suffisante. C'est pourquoi la page de Wooledge BashFAQ (voir ci-dessous) explique comment réorganiser les arguments. Mais j'aimerais éviter de créer plusieurs tableaux au cas où la liste d'arguments serait assez longue.
Étant donné shift
que ne prend pas en charge le saut d'arguments individuels au milieu de la liste des paramètres, je ne sais pas quelle est la manière simple de mettre en œuvre ce que je demande.
J'aimerais savoir si quelqu'un a des solutions pour supprimer les arguments du milieu de la liste des paramètres sans créer un tout nouveau tableau.
Pages que j'ai déjà vues:
- http://mywiki.wooledge.org/ComplexOptionParsing#Rearranging_arguments
- http://mywiki.wooledge.org/BashFAQ/035
- Utilisation de getopts dans le script shell bash pour obtenir des options de ligne de commande longues et courtes
- http://wiki.bash-hackers.org/scripting/posparams
- http://wiki.bash-hackers.org/howto/getopts_tutorial
- cas d'argument bash pour args dans $ @
- Quelle est la manière canonique d'implémenter des options indépendantes de l'ordre dans les scripts bash?
- Comment gérer les commutateurs dans un script shell?
Réponses:
POSIX, l'analyse des options doit s'arrêter au
--
ou au premier argument sans option (ou sans option) selon la première éventualité. Donc dansqui est en
file1
, donccp
doivent copier récursive tousfile1
,-t
,/mybackup
etfile2
dans le-f
répertoire.GNU
getopt(3)
cependant (que GNUcp
utilise pour analyser les options (et ici vous utilisez GNUcp
puisque vous utilisez l'-t
option spécifique à GNU )), à moins que la$POSIXLY_CORRECT
variable d'environnement ne soit définie, accepte les options après les arguments. Il est donc en fait équivalent à l'analyse de style d'option POSIX:Le
getopts
shell intégré, même dans le shell GNU (bash
), ne gère que le style POSIX. Il ne prend pas non plus en charge les options longues ou les options avec des arguments facultatifs.Si vous souhaitez analyser les options de la même manière que GNU
cp
, vous devrez utiliser l'getopt(3)
API GNU . Pour cela, si sous Linux, vous pouvez utiliser l'getopt
utilitaire amélioré deutil-linux
( cette version améliorée de lagetopt
commande a également été portée sur d'autres Unices comme FreeBSD ).Cela
getopt
réorganisera les options de manière canonique, ce qui vous permettra de les analyser simplement avec unewhile/case
boucle.Vous l'utiliseriez généralement comme:
Notez également que cela
getopt
analysera les options de la même manière que GNUcp
. En particulier, il prend en charge les options longues (et les saisit en abrégé) et honore les$POSIXLY_CORRECT
variables d'environnement (qui, une fois définies, désactivent la prise en charge des options après les arguments) de la même manière que GNUcp
.Notez que l'utilisation de gdb et l'impression des arguments
getopt_long()
reçus peuvent aider à construire les paramètres pourgetopt(1)
:Ensuite, vous pouvez utiliser
getopt
comme:N'oubliez pas que
cp
la liste des options prises en charge par GNU peut changer d'une version à la suivante et qu'ellegetopt
ne pourra pas vérifier si vous transmettez une valeur légale à l'--sparse
option par exemple.la source
while [ "$#" -gt 0 ]
juste iowhile (($#))
? Est-ce juste pour éviter un bashisme?(($#))
c'est plus un kshisme .Ainsi, chaque fois qu'il
getopts
traite un argument, il ne s'attend pas à ce qu'il définit la variable shell$OPTIND
au numéro suivant dans la liste d'arguments qu'il doit traiter et renvoie autre que 0. Si$OPTIND
est défini sur une valeur de 1,getopts
est spécifié par POSIX pour accepter un nouvelle liste d'arguments. Ainsi, cela ne fait que surveiller legetopts
retour, enregistre les incréments d'un compteur plus$OPTIND
pour tout retour échoué, éloigne les arguments échoués et réinitialise$OPTIND
chaque essai échoué. Vous pouvez l'utiliser commeopts "$@"
- bien que vous souhaitiez personnaliser lacase
boucle ou bien l'enregistrer dans une variable et changer cette section eneval $case
.Lors de son exécution, il définit
$args
tous les arguments quigetopts
n'ont pas été traités ... alors ...PRODUCTION
Cela fonctionne
bash
,dash
,zsh
,ksh93
,mksh
... eh bien, je cesser d' essayer à ce moment - là. Dans chaque coquille, il a également obtenu$[Rtf]flag
et$targ
. Le fait est que tous les nombres des arguments quigetopts
ne voulaient pas être traités sont restés.Changer le style des options n'a fait aucune différence non plus. Cela a fonctionné comme
-Rf -t/mybackup
ou-R -f -t /mybackup
. Cela a fonctionné au milieu de la liste, à la fin de la liste ou en tête de liste ...Pourtant, le meilleur moyen est simplement de coller un
--
pour la fin des options sur votre liste d'arguments, puis de le faireshift "$(($OPTIND-1))"
à la fin d'ungetopts
cycle de traitement. De cette façon, vous supprimez tous les paramètres traités et conservez l'extrémité arrière de la liste des arguments.Une chose que j'aime faire est de traduire les options longues en courtes - et je le fais de manière très similaire, c'est pourquoi cette réponse est venue facilement - avant de courir
getopts
.la source
cp -t --file foo
oucp -- --file foo
) et ne gérerait pas les options saisies en abrégé (--fi
...), ni la--target=/dest
syntaxe.getopts
chose par une fonction beaucoup plus simple.opts()
a une certaine incidence sur votre propre réponse, car ilopts()
fonctionne dans une seule boucle - en touchant chaque argument mais une fois - et le fait de manière fiable (aussi près que je peux dire) , de manière portable et sans un seul sous-shell.-R
,-t /mybackup
,-f
). Je vais garder mon vote bas pour l'instant car il est toujours obscurci, vous utilisez$a
non initialisé etargs= opts...
laissera probablementargs
non défini (ou défini sur ce qu'il était auparavant) après lesopts
retours dans de nombreux shells (y compris bash).bash
- je déteste ça. À mon avis, si la fonction est une fonction shell actuelle qui devrait être conservée. J'aborde ces choses - car la fonction actuelle, avec plus de tests, pourrait être robuste pour gérer tous les cas, et même pour signaler l' argument avec son option précédente, mais je ne suis pas d'accord pour dire qu'elle est obscurcie . Tel qu'il est écrit, c'est le moyen le plus simple et le plus direct d'accomplir sa tâche auquel je puisse penser.test
ing puisshift
ing n'a pas de sens quand dans tous lesshift
cas d' échec vous devriezreturn
. Il n'est pas prévu de faire autrement.