Пример использования getopts в bash
Я хочу позвонить myscript
файл:
$ ./myscript -s 45 -p any_string
или
$ ./myscript -h >>> should display help
$ ./myscript >>> should display help
мои требования:
-
getopt
сюда входных аргументов - проверяем, что
-s
существует, если не ошибка возврата - проверьте, что значение после
-s
45 или 90 - проверяем, что
-p
существует, и есть входная строка после - если пользователь вводит
./myscript -h
или просто./myscript
затем отобразить справку
Я пробовал до сих пор этот код:
#!/bin/bash
while getopts "h:s:" arg; do
case $arg in
h)
echo "usage"
;;
s)
strength=$OPTARG
echo $strength
;;
esac
done
но с этим кодом я получаю ошибки. Как это сделать с Bash и getopt
?
6 ответов
#!/bin/bash
usage() { echo "Usage: [-s <45|90>] [-p <string>]" 1>&2; exit 1; }
while getopts ":s:p:" o; do
case "${o}" in
s)
s=${OPTARG}
((s == 45 || s == 90)) || usage
;;
p)
p=${OPTARG}
;;
*)
usage
;;
esac
done
shift $((OPTIND-1))
if [ -z "${s}" ] || [ -z "${p}" ]; then
usage
fi
echo "s = ${s}"
echo "p = ${p}"
пример работает:
$ ./myscript.sh
Usage: ./myscript.sh [-s <45|90>] [-p <string>]
$ ./myscript.sh -h
Usage: ./myscript.sh [-s <45|90>] [-p <string>]
$ ./myscript.sh -s "" -p ""
Usage: ./myscript.sh [-s <45|90>] [-p <string>]
$ ./myscript.sh -s 10 -p foo
Usage: ./myscript.sh [-s <45|90>] [-p <string>]
$ ./myscript.sh -s 45 -p foo
s = 45
p = foo
$ ./myscript.sh -s 90 -p bar
s = 90
p = bar
проблема с исходным кодом заключается в том, что:
-
h:
ожидает параметр, где он не должен, поэтому измените его на justh
(без двоеточия) - ждать
-p any_string
, вам необходимо добавитьp:
в списке аргументов
базовый синтаксис getopts
is (см.:man bash
):
getopts OPTSTRING VARNAME [ARGS...]
где:
-
OPTSTRING
- строка со списком ожидаемых аргументы,-
h
- проверьте параметр-h
без параметры; дает ошибку на неподдерживаемые параметры; -
h:
- проверьте параметр-h
С параметр; выдает ошибки при неподдерживаемых параметрах; -
abc
- проверьте параметры-a
,-b
,-c
; дает ошибки при неподдерживаемых параметрах; -
:abc
- проверьте параметры-a
,-b
,-c
; молчание ошибки при неподдерживаемых параметрах;Примечания: другими словами, двоеточие перед параметрами позволяет обрабатывать ошибки в коде. Переменная будет содержать
?
в случае неподдерживаемого варианта,:
в случае отсутствия значения.
-
OPTARG
- установлено значение текущего аргумента,-
OPTERR
- указывает, если Bash должен отображать ошибку сообщения.
таким образом, код может быть:
#!/usr/bin/env bash
usage() { echo " usage:" && grep " .)\ #" ; exit 0; }
[ $# -eq 0 ] && usage
while getopts ":hs:p:" arg; do
case $arg in
p) # Specify p value.
echo "p is ${OPTARG}"
;;
s) # Specify strength, either 45 or 90.
strength=${OPTARG}
[ $strength -eq 45 -o $strength -eq 90 ] \
&& echo "Strength is $strength." \
|| echo "Strength needs to be either 45 or 90, $strength found instead."
;;
h | *) # Display help.
usage
exit 0
;;
esac
done
пример использования:
$ ./foo.sh
./foo.sh usage:
p) # Specify p value.
s) # Specify strength, either 45 or 90.
h | *) # Display help.
$ ./foo.sh -s 123 -p any_string
Strength needs to be either 45 or 90, 123 found instead.
p is any_string
$ ./foo.sh -s 90 -p any_string
Strength is 90.
p is any_string
посмотреть: небольшой учебник getopts на Bash хакеры Wiki
пример упакован с getopt
(мой дистрибутив поставил его в /usr/share/getopt/getopt-parse.bash
) похоже, что он охватывает все ваши случаи:
#!/bin/bash
# A small example program for using the new getopt(1) program.
# This program will only work with bash(1)
# An similar program using the tcsh(1) script language can be found
# as parse.tcsh
# Example input and output (from the bash prompt):
# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "
# Option a
# Option c, no argument
# Option c, argument `more'
# Option b, argument ` very long '
# Remaining arguments:
# --> `par1'
# --> `another arg'
# --> `wow!*\?'
# Note that we use `"$@"' to let each command-line parameter expand to a
# separate word. The quotes around `$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \
-n 'example.bash' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
while true ; do
case "" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument \`'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "" in
"") echo "Option c, no argument"; shift 2 ;;
*) echo "Option c, argument \`'" ; shift 2 ;;
esac ;;
--) shift ; break ;;
*) echo "Internal error!" ; exit 1 ;;
esac
done
echo "Remaining arguments:"
for arg do echo '--> '"\`$arg'" ; done
Я знаю, что на это уже ответили, но для записи и для тех, у кого такие же запросы, как у меня, я решил опубликовать этот связанный ответ. Код переполнен комментариями для объяснения кода.
обновленный ответ:
сохраните файл как getopt.sh
:
#!/bin/bash
function get_variable_name_for_option {
local OPT_DESC=
local OPTION=
local VAR=$(echo ${OPT_DESC} | sed -e "s/.*\[\?-${OPTION} \([A-Z_]\+\).*//g" -e "s/.*\[\?-\(${OPTION}\).*/FLAG/g")
if [[ "${VAR}" == "" ]]; then
echo ""
else
echo ${VAR}
fi
}
function parse_options {
local OPT_DESC=
local INPUT=$(get_input_for_getopts "${OPT_DESC}")
shift
while getopts ${INPUT} OPTION ${@};
do
[ ${OPTION} == "?" ] && usage
VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
[ "${VARNAME}" != "" ] && eval "${VARNAME}=${OPTARG:-true}" # && printf "\t%s\n" "* Declaring ${VARNAME}=${!VARNAME} -- OPTIONS='$OPTION'"
done
check_for_required "${OPT_DESC}"
}
function check_for_required {
local OPT_DESC=
local REQUIRED=$(get_required "${OPT_DESC}" | sed -e "s/\://g")
while test -n "${REQUIRED}"; do
OPTION=${REQUIRED:0:1}
VARNAME=$(get_variable_name_for_option "${OPT_DESC}" "${OPTION}")
[ -z "${!VARNAME}" ] && printf "ERROR: %s\n" "Option -${OPTION} must been set." && usage
REQUIRED=${REQUIRED:1}
done
}
function get_input_for_getopts {
local OPT_DESC=
echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/:/g" -e "s/[][ -]//g"
}
function get_optional {
local OPT_DESC=
echo ${OPT_DESC} | sed -e "s/[^[]*\(\[[^]]*\]\)[^[]*//g" -e "s/\([a-zA-Z]\) [A-Z_]\+/:/g" -e "s/[][ -]//g"
}
function get_required {
local OPT_DESC=
echo ${OPT_DESC} | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/:/g" -e "s/\[[^[]*\]//g" -e "s/[][ -]//g"
}
function usage {
printf "Usage:\n\t%s\n" " ${OPT_DESC}"
exit 10
}
тогда вы можете использовать его следующим образом:
#!/bin/bash
#
# [ and ] defines optional arguments
#
# location to getopts.sh file
source ./getopt.sh
USAGE="-u USER -d DATABASE -p PASS -s SID [ -a START_DATE_TIME ]"
parse_options "${USAGE}" ${@}
echo ${USER}
echo ${START_DATE_TIME}
ответ:
недавно мне нужно было использовать общий подход. Я столкнулся с этим. решение:
#!/bin/bash
# Option Description:
# -------------------
#
# Option description is based on getopts bash builtin. The description adds a variable name feature to be used
# on future checks for required or optional values.
# The option description adds "=>VARIABLE_NAME" string. Variable name should be UPPERCASE. Valid characters
# are [A-Z_]*.
#
# A option description example:
# OPT_DESC="a:=>A_VARIABLE|b:=>B_VARIABLE|c=>C_VARIABLE"
#
# -a option will require a value (the colon means that) and should be saved in variable A_VARIABLE.
# "|" is used to separate options description.
# -b option rule applies the same as -a.
# -c option doesn't require a value (the colon absense means that) and its existence should be set in C_VARIABLE
#
# ~$ echo get_options ${OPT_DESC}
# a:b:c
# ~$
#
# Required options
REQUIRED_DESC="a:=>REQ_A_VAR_VALUE|B:=>REQ_B_VAR_VALUE|c=>REQ_C_VAR_FLAG"
# Optional options (duh)
OPTIONAL_DESC="P:=>OPT_P_VAR_VALUE|r=>OPT_R_VAR_FLAG"
function usage {
IFS="|"
printf "%s"
for i in ${REQUIRED_DESC};
do
VARNAME=$(echo $i | sed -e "s/.*=>//g")
printf " %s" "-${i:0:1} $VARNAME"
done
for i in ${OPTIONAL_DESC};
do
VARNAME=$(echo $i | sed -e "s/.*=>//g")
printf " %s" "[-${i:0:1} $VARNAME]"
done
printf "\n"
unset IFS
exit
}
# Auxiliary function that returns options characters to be passed
# into 'getopts' from a option description.
# Arguments:
# : The options description (SEE TOP)
#
# Example:
# OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
# OPTIONS=$(get_options ${OPT_DESC})
# echo "${OPTIONS}"
#
# Output:
# "h:f:PW"
function get_options {
echo | sed -e "s/\([a-zA-Z]\:\?\)=>[A-Z_]*|\?//g"
}
# Auxiliary function that returns all variable names separated by '|'
# Arguments:
# : The options description (SEE TOP)
#
# Example:
# OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
# VARNAMES=$(get_values ${OPT_DESC})
# echo "${VARNAMES}"
#
# Output:
# "H_VAR|F_VAR|P_VAR|W_VAR"
function get_variables {
echo | sed -e "s/[a-zA-Z]\:\?=>\([^|]*\)//g"
}
# Auxiliary function that returns the variable name based on the
# option passed by.
# Arguments:
# : The options description (SEE TOP)
# : The option which the variable name wants to be retrieved
#
# Example:
# OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
# H_VAR=$(get_variable_name ${OPT_DESC} "h")
# echo "${H_VAR}"
#
# Output:
# "H_VAR"
function get_variable_name {
VAR=$(echo | sed -e "s/.*\:\?=>\([^|]*\).*//g")
if [[ ${VAR} == ]]; then
echo ""
else
echo ${VAR}
fi
}
# Gets the required options from the required description
REQUIRED=$(get_options ${REQUIRED_DESC})
# Gets the optional options (duh) from the optional description
OPTIONAL=$(get_options ${OPTIONAL_DESC})
# or... $(get_options "${OPTIONAL_DESC}|${REQUIRED_DESC}")
# The colon at starts instructs getopts to remain silent
while getopts ":${REQUIRED}${OPTIONAL}" OPTION
do
[[ ${OPTION} == ":" ]] && usage
VAR=$(get_variable_name "${REQUIRED_DESC}|${OPTIONAL_DESC}" ${OPTION})
[[ -n ${VAR} ]] && eval "$VAR=${OPTARG}"
done
shift $(($OPTIND - 1))
# Checks for required options. Report an error and exits if
# required options are missing.
# Using function version ...
VARS=$(get_variables ${REQUIRED_DESC})
IFS="|"
for VARNAME in $VARS;
do
[[ -v ${VARNAME} ]] || usage
done
unset IFS
# ... or using IFS Version (no function)
OLDIFS=${IFS}
IFS="|"
for i in ${REQUIRED_DESC};
do
VARNAME=$(echo $i | sed -e "s/.*=>//g")
[[ -v ${VARNAME} ]] || usage
printf "%s %s %s\n" "-${i:0:1}" "${!VARNAME:=present}" "${VARNAME}"
done
IFS=${OLDIFS}
Я не тестировал это грубо, поэтому у меня могли быть некоторые ошибки.
POSIX 7 пример
также стоит проверить пример из стандарта:http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html
aflag=
bflag=
while getopts ab: name
do
case $name in
a) aflag=1;;
b) bflag=1
bval="$OPTARG";;
?) printf "Usage: %s: [-a] [-b value] args\n"
exit 2;;
esac
done
if [ ! -z "$aflag" ]; then
printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"
и тогда мы можем попробовать:
$ sh a.sh
Remaining arguments are:
$ sh a.sh -a
Option -a specified
Remaining arguments are:
$ sh a.sh -b
No arg for -b option
Usage: a.sh: [-a] [-b value] args
$ sh a.sh -b myval
Option -b "myval" specified
Remaining arguments are:
$ sh a.sh -a -b myval
Option -a specified
Option -b "myval" specified
Remaining arguments are:
$ sh a.sh remain
Remaining arguments are: remain
$ sh a.sh -- -a remain
Remaining arguments are: -a remain
протестировано в Ubuntu 17.10,sh
Дэш 0.5.8.
использовать getopt
почему getopt?
чтобы проанализировать разработанные аргументы командной строки, чтобы избежать путаницы и уточнить параметры, которые мы анализируем, чтобы читатель команд мог понять, что происходит.
что такое getopt?
getopt
используется для разбиения (разбора) параметров в командных строках для легкого разбора по процедурам оболочки и проверки законных параметров. Он использует GNU getopt(3)
процедуры сделать это.
getopt
может иметь следующие типы опций.
- нет-значения параметров
- параметры пары ключ-значение
Примечание: в этом документе во время объяснения синтаксиса:
- что-либо внутри [ ] является необязательным параметром в синтаксисе/примерах.
- является держателем места, что означает, что он должен быть заменен фактическим значением.
КАК ИСПОЛЬЗОВАТЬ getopt
?
Синтаксис: Первая Форма
getopt optstring parameters
примеры:
# This is correct
getopt "hv:t::" "-v 123 -t123"
getopt "hv:t::" "-v123 -t123" # -v and 123 doesn't have whitespace
# -h takes no value.
getopt "hv:t::" "-h -v123"
# This is wrong. after -t can't have whitespace.
# Only optional params cannot have whitespace between key and value
getopt "hv:t::" "-v 123 -t 123"
# Multiple arguments that takes value.
getopt "h:v:t::g::" "-h abc -v 123 -t21"
# Multiple arguments without value
# All of these are correct
getopt "hvt" "-htv"
getopt "hvt" "-h -t -v"
getopt "hvt" "-tv -h"
здесь H,v, t-это параметры, а-h-v-t-это то, как параметры должны быть заданы в командной строке.
- ' h ' - это опция без значения.
- 'v:' означает, что опция-v имеет значение и является обязательным вариантом. ': 'средство имеет значение.
- 't::' подразумевает, что опция-t имеет значение, но является необязательной. '::' средства необязательный.
в необязательном параметре значение не может иметь разделение пробелов с помощью опции. Итак, в Примере"- t123 " - T-это опция 123-это значение.
Синтаксис: Вторая Форма
getopt [getopt_options] [--] [optstring] [parameters]
здесь после getopt делится на пять частей
- сама команда, т. е. getopt
- getopt_options, он описывает, как анализировать аргументы. одиночные варианты черточки длинные, двойные варианты черточки.
- --, отделяет getopt_options из параметров, которые вы хотите проанализировать, и разрешенные короткие параметры
- короткие варианты, берется сразу после -- находится. Так же, как синтаксис формы first.
- параметры, это параметры, которые вы передали в программу. Параметры, которые вы хотите обработать и получить фактические значения, установленные на них.
примеры
getopt -l "name:,version::,verbose" -- "n:v::V" "--name=Karthik -version=5.2 -verbose"
Синтаксис: Третья Форма
getopt [getopt_options] [-o options] [--] [optstring] [parameters]
здесь после разделения getopt на пять частей!--19-->
- сама команда, т. е. getopt
- getopt_options, он описывает, как анализировать аргументы. одиночные варианты черточки длинные, двойные варианты черточки.
- короткие опции, т. е.-o или --options. Так же, как синтаксис формы, но с опцией "-o" и перед "--" (двойная тире).
- --, отделяет getopt_options от опций, которые вы хотите разобрать, и разрешенных коротких опций
- в параметры, это параметры, которые вы передали в программу. Параметры, которые вы хотите обработать и получить фактические значения, установленные на них.
примеры
getopt -l "name:,version::,verbose" -a -o "n:v::V" -- "-name=Karthik -version=5.2 -verbose"
GETOPT_OPTIONS
getopt_options изменяет способ синтаксического анализа параметров командной строки.
Ниже приведены некоторые из getopt_options
вариант: - l или --longoptions
означает, что команда getopt должна разрешить многозначные опции распознанный. Несколько параметров разделяются запятыми.
например, --name=Karthik
- это длинная опция, отправленная в командной строке. В getopt использование длинных опций похоже на
getopt "name:,version" "--name=Karthik"
поскольку указано name:, опция должна содержать значение
опция: - a или --alternative
означает, что команда getopt должна разрешить длинную опцию иметь одну тире '- 'вместо двойного тире '--'.
например, вместо --name=Karthik
вы можете использовать только -name=Karthik
getopt "name:,version" "-name=Karthik"
полный пример скрипта с кодом:
#!/bin/bash
# filename: commandLine.sh
# author: @theBuzzyCoder
showHelp() {
# `cat << EOF` This means that cat should stop reading when EOF is detected
cat << EOF
Usage: ./installer -v <espo-version> [-hrV]
Install Pre-requisites for EspoCRM with docker in Development mode
-h, -help, --help Display help
-v, -espo-version, --espo-version Set and Download specific version of EspoCRM
-r, -rebuild, --rebuild Rebuild php vendor directory using composer and compiled css using grunt
-V, -verbose, --verbose Run script in verbose mode. Will print out each step of execution.
EOF
# EOF is found above and hence cat command stops reading. This is equivalent to echo but much neater when printing out.
}
export version=0
export verbose=0
export rebuilt=0
# $@ is all command line parameters passed to the script.
# -o is for short options like -v
# -l is for long options with double dash like --version
# the comma separates different long options
# -a is for long options with single dash like -version
options=$(getopt -l "help,version:,verbose,rebuild,dryrun" -o "hv:Vrd" -a -- "$@")
# set --:
# If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters
# are set to the arguments, even if some of them begin with a ‘-’.
eval set -- "$options"
while true
do
case in
-h|--help)
showHelp
exit 0
;;
-v|--version)
shift
export version=
;;
-V|--verbose)
export verbose=1
set -xv # Set xtrace and verbose mode.
;;
-r|--rebuild)
export rebuild=1
;;
--)
shift
break;;
esac
shift
done
работает этот скрипт:
# With short options grouped together and long option
# With double dash '--version'
bash commandLine.sh --version=1.0 -rV
# With short options grouped together and long option
# With single dash '-version'
bash commandLine.sh -version=1.0 -rV
# OR with short option that takes value, value separated by whitespace
# by key
bash commandLine.sh -v 1.0 -rV
# OR with short option that takes value, value without whitespace
# separation from key.
bash commandLine.sh -v1.0 -rV
# OR Separating individual short options
bash commandLine.sh -v1.0 -r -V