2166 votes

Comment analyser les arguments de la ligne de commande dans bash?

Dites que j'ai un script qui est appelé avec cette ligne:

 ./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
 

ou celui-ci:

 ./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile 
 

Quelle est la manière acceptée d'analyser ceci de telle sorte que dans chaque cas (ou une combinaison des deux) $v , $f , et $d seront tous mis à true et $outFile sera égal à /fizz/someOtherFile ?

3011voto

Richard Bronosky Points 3163

Mise à jour: Regardez en dessous de la "Aide getopts" répondez pour voir le "sans getopts" réponse, j'ai ajouté. Pour beaucoup de gens qui vont être préférable.

À l'aide de getopt[s]

de: http://mywiki.wooledge.org/BashFAQ/035#getopts

N'utilisez jamais de getopt(1). getopt ne peut pas gérer le vide des arguments des chaînes, ou des arguments intégré des espaces. Veuillez oublier qu'il a existé.

Le shell POSIX (et d'autres) offrent getopts ce qui est sûr à utiliser à la place. Ici est simpliste getopts exemple:

#!/bin/sh

# A POSIX variable
OPTIND=1         # Reset in case getopts has been used previously in the shell.

# Initialize our own variables:
output_file=""
verbose=0

while getopts "h?vf:" opt; do
    case "$opt" in
    h|\?)
        show_help
        exit 0
        ;;
    v)  verbose=1
        ;;
    f)  output_file=$OPTARG
        ;;
    esac
done

shift $((OPTIND-1))

[ "$1" = "--" ] && shift

echo "verbose=$verbose, output_file='$output_file', Leftovers: $@"

# End of file

Les avantages de l' getoptssont: 1. Il est portable et fonctionne dans par exemple le tableau de bord.
1. Il peut gérer des choses comme -vf filename dans les attendus d'Unix, automatiquement.

L'inconvénient de l' getopts , c'est qu'il ne peut gérer que les options courtes (-h, pas --help) sans ruse.

Il y a un getopts tutoriel qui explique ce que l'ensemble de la syntaxe et des noms de variables. En bash, il est également help getopts, ce qui pourrait être instructif.

L'utilisation de droite bash sans getopt[s]

J'ai d'abord répondu à la question que l'OP a demandé. Cette Q/r est l'objet de beaucoup d'attention, donc, je devrais vous offrons également la non-magique façon de le faire. Je vais développer sur guneysus de réponse pour résoudre le méchant sed et comprennent Tobias Kienzler de la suggestion.

Deux des façons les plus courantes pour passer la valeur de clé de paire arguments sont les suivants:

Séparés Par Un Espace

L'utilisation de la ./myscript.sh -e conf -s /etc -l /usr/lib /etc/hosts

#!/bin/bash
while [[ $# > 1 ]]
do
key="$1"
shift

case $key in
    -e|--extension)
    EXTENSION="$1"
    shift
    ;;
    -s|--searchpath)
    SEARCHPATH="$1"
    shift
    ;;
    -l|--lib)
    LIBPATH="$1"
    shift
    ;;
    --default)
    DEFAULT=YES
    shift
    ;;
    *)
            # unknown option
    ;;
esac
done
echo FILE EXTENSION  = "${EXTENSION}"
echo SEARCH PATH     = "${SEARCHPATH}"
echo LIBRARY PATH    = "${LIBPATH}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)
if [[ -n $1 ]]; then
    echo "Last line of file specified as non-opt/last argument:"
    tail -1 $1
fi

Est Égal Séparés

#!/bin/bash

for i in "$@"
do
case $i in
    -e=*|--extension=*)
    EXTENSION="${i#*=}"
    shift
    ;;
    -s=*|--searchpath=*)
    SEARCHPATH="${i#*=}"
    shift
    ;;
    -l=*|--lib=*)
    LIBPATH="${i#*=}"
    shift
    ;;
    --default)
    DEFAULT=YES
    shift
    ;;
    *)
            # unknown option
    ;;
esac
done
echo "FILE EXTENSION  = ${EXTENSION}"
echo "SEARCH PATH     = ${SEARCHPATH}"
echo "LIBRARY PATH    = ${LIBPATH}"
echo "Number files in SEARCH PATH with EXTENSION:" $(ls -1 "${SEARCHPATH}"/*."${EXTENSION}" | wc -l)
if [[ -n $1 ]]; then
    echo "Last line of file specified as non-opt/last argument:"
    tail -1 $1
fi

Afin de mieux comprendre ${i#*=} de la recherche pour "sous-Chaîne de Suppression de" dans ce guide. Il est fonctionnellement équivalent à `sed 's/[^=]*=//' <<< "$i"` qui appelle une inutile sous-processus ou `echo "$i" | sed 's/[^=]*=//'` qui appelle deux inutile sous-processus.

145voto

guneysus Points 485

de: digitalpeer.com avec des modifications mineures

Utilisation myscript.sh -p=my_prefix -s=dirname -l=libname

 #!/bin/bash
for i in "$@"
do
case $i in
    -p=*|--prefix=*)
    PREFIX="${i#*=}"

    ;;
    -s=*|--searchpath=*)
    SEARCHPATH="${i#*=}"
    ;;
    -l=*|--lib=*)
    DIR="${i#*=}"
    ;;
    --default)
    DEFAULT=YES
    ;;
    *)
            # unknown option
    ;;
esac
done
echo PREFIX = ${PREFIX}
echo SEARCH PATH = ${SEARCHPATH}
echo DIRS = ${DIR}
 

Pour mieux comprendre ${i#*=} recherchez «Retrait de la sous-chaîne» dans ce guide . Il est fonctionnellement équivalent à `sed 's/[^=]*=//' <<< "$i"` qui appelle un sous-processus inutile ou `echo "$i" | sed 's/[^=]*=//'` qui appelle deux sous-processus inutiles.

108voto

Matt J Points 15475

getopt()/getopts() est une bonne option. Volés à partir d' ici:

La simple utilisation de "getopt" est indiqué dans ce mini-script:

#!/bin/bash
echo "Before getopt"
for i
do
  echo $i
done
args=`getopt abc:d $*`
set -- $args
echo "After getopt"
for i
do
  echo "-->$i"
done

Ce que nous avons dit, c'est que tout -un, -b, -c ou-d sera autorisé, mais que c est suivi par un argument (le "c:" dit que).

Si nous appelons cela "g" et de l'essayer:

bash-2.05a$ ./g -abc foo
Before getopt
-abc
foo
After getopt
-->-a
-->-b
-->-c
-->foo
-->--

Nous commençons avec deux arguments, et "getopt" en dehors des pauses les options et les met chacun dans son propre argument. Il a également ajouté "--".

44voto

Shane Day Points 21

Je suis environ 4 ans de retard à cette question, mais veulent redonner. J’ai utilisé les réponses précédentes comme point de départ de ranger mon vieux adhoc param analyse. J’ai ensuite refactorisé le code de modèle suivant. Il gère les params de longs et courts, à l’aide de = ou arguments séparés, ainsi que plusieurs params courts regroupés de l’espace. Enfin elle réinsère d’arguments non-param dans le $1, $2... variables. J’espère que c’est utile.

15voto

Alek Points 81

Je pense que celui-ci est assez simple à utiliser :

Exemple d’appel :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X